Railway Operation Simulator  v2.6.1
A railway simulator for Windows
TrackUnit.cpp
Go to the documentation of this file.
1 // TrackUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder 10.2.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 #include <Classes.hpp>
27 #include <Controls.hpp>
28 #include <StdCtrls.hpp>
29 #include <Forms.hpp>
30 #include <Buttons.hpp>
31 #include <ExtCtrls.hpp>
32 #include <Menus.hpp>
33 #include <Dialogs.hpp>
34 #include <Graphics.hpp>
35 #include <ComCtrls.hpp>
36 #include <fstream>
37 #include <vector>
38 #include <algorithm> //for std::find
39 #include <vcl.h>
40 
41 #pragma hdrstop
42 
43 #include "TrackUnit.h"
44 #include "Utilities.h"
45 // #include "DisplayUnit.h" included in header file
46 #include "GraphicUnit.h"
47 #include "TextUnit.h"
48 #include "TrainUnit.h"
49 
50 #pragma package(smart_init)
51 // ---------------------------------------------------------------------------
52 
55 
56 // ---------------------------------------------------------------------------
57 
58 // FIXED TRACK :-
59 
60 // Constructor to build TrackPieces from array
61 
62 TFixedTrackPiece::TFixedTrackPiece(int SpeedTagVal, TTrackType TrackTypeVal, int LkVal[4], TConfiguration ConfigVal[4], Graphics::TBitmap* GraphicPtrVal,
63  Graphics::TBitmap* SmallGraphicPtrVal): SpeedTag(SpeedTagVal), TrackType(TrackTypeVal), GraphicPtr(GraphicPtrVal), SmallGraphicPtr(SmallGraphicPtrVal)
64 {
65  for(int x = 0; x < 4; x++)
66  {
67  Link[x] = LkVal[x];
68  Config[x] = ConfigVal[x];
69  }
70 // NamedLocationElements 76, 77, 78, 79, 96, 129, 130, 131, 145 & 146 (platforms, concourses, footcrossings & named non-station locations)
71  FixedNamedLocationElement = false; // underpasses (144 & 145 added at v2.3.1
72  if(SpeedTagVal == 76)
74  else if(SpeedTagVal == 77)
76  else if(SpeedTagVal == 78)
78  else if(SpeedTagVal == 79)
80  else if(SpeedTagVal == 96)
82  else if(SpeedTagVal == 129)
84  else if(SpeedTagVal == 130)
86  else if(SpeedTagVal == 131)
88  else if(SpeedTagVal == 145)
90  else if(SpeedTagVal == 146)
92 }
93 
94 // ---------------------------------------------------------------------------
95 
96 TFixedTrackPiece::TFixedTrackPiece(): SpeedTag(0), TrackType(Erase), GraphicPtr(RailGraphics->bmSolidBgnd), SmallGraphicPtr(RailGraphics->smSolidBgnd),
97  FixedNamedLocationElement(false) // default values
98 {
99  for(int x = 0; x < 4; x++)
100  {
101  Link[x] = -1; // -1 & NotSet are the markers for 'unused' respectively
102  Config[x] = NotSet;
103  }
104 }
105 
106 // ---------------------------------------------------------------------------
107 void TFixedTrackPiece::PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
108 {
109  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotFixedTrackElement," + AnsiString(HLocInput) + "," +
110  AnsiString(VLocInput));
111  Display->PlotOutput(33, HLocInput * 16, VLocInput * 16, GraphicPtr);
112  Utilities->CallLogPop(1331);
113 }
114 
115 // ---------------------------------------------------------------------------
116 
117 // VARIABLE TRACK :-
118 
119 // ---------------------------------------------------------------------------
120 
122 {
123  if((this->HLoc == RHElement.HLoc) && (this->VLoc == RHElement.VLoc) && (this->SpeedTag == RHElement.SpeedTag))
124  return true;
125  else
126  return false;
127 }
128 
129 // ---------------------------------------------------------------------------
130 
132 {
133  if((this->HLoc != RHElement.HLoc) || (this->VLoc != RHElement.VLoc) || (this->SpeedTag != RHElement.SpeedTag))
134  return true;
135  else
136  return false;
137 }
138 
139 // ---------------------------------------------------------------------------
140 
142  // 'Variable' in the sense that element might be striped or non-striped
143 {
144  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotVariableTrackElement");
145  Graphics::TBitmap *GraphicOutput = GraphicPtr;
146 
147  if(LocationName == "")
148  {
149  switch(SpeedTag)
150  {
151  case 76: // t platform
152  GraphicOutput = RailGraphics->gl76Striped;
153  break;
154 
155  case 77: // h platform
156  GraphicOutput = RailGraphics->bm77Striped;
157  break;
158 
159  case 78: // v platform
160  GraphicOutput = RailGraphics->bm78Striped;
161  break;
162 
163  case 79: // r platform
164  GraphicOutput = RailGraphics->gl79Striped;
165  break;
166 
167  case 96: // concourse
168  GraphicOutput = RailGraphics->ConcourseStriped;
169  break;
170 
171  case 129: // v footbridge
172  GraphicOutput = RailGraphics->gl129Striped;
173  break;
174 
175  case 130: // h footbridge
176  GraphicOutput = RailGraphics->gl130Striped;
177  break;
178 
179  case 131: // non-station named loc
180  GraphicOutput = RailGraphics->bmNameStriped;
181  break;
182 
183  case 145: // v underpass
184  GraphicOutput = RailGraphics->gl145Striped;
185  break;
186 
187  case 146: // h underpass
188  GraphicOutput = RailGraphics->gl146Striped;
189  break;
190 
191  default:
192  GraphicOutput = GraphicPtr;
193  break;
194  }
195  }
196  Disp->PlotOutput(34, HLoc * 16, VLoc * 16, GraphicOutput);
197  Utilities->CallLogPop(1332);
198 }
199 
200 // ---------------------------------------------------------------------------
201 
202 AnsiString TTrackElement::LogTrack(int Caller) const
203  // for debugging when passes as a call parameter
204 {
205  AnsiString LogString = "TrkEl:-," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," +
206  AnsiString(TrainIDOnBridgeTrackPos01) + "," + AnsiString(TrainIDOnBridgeTrackPos23) + ",EndTrkEl,";
207 
208  return LogString;
209 }
210 
211 // ---------------------------------------------------------------------------
212 
213 bool TMapComp:: operator()(const THVPair& lower, const THVPair& higher) const // HLoc VLoc
214 {
215  if(lower.second < higher.second)
216  {
217  return true;
218  }
219  else if(lower.second > higher.second)
220  {
221  return false;
222  }
223  else if(lower.second == higher.second)
224  {
225  if(lower.first < higher.first)
226  {
227  return true;
228  }
229  }
230  return false;
231 }
232 
233 // ---------------------------------------------------------------------------
234 // PrefDirElement Functions
235 // ---------------------------------------------------------------------------
236 
237 TPrefDirElement::TPrefDirElement(TTrackElement ElementIn, int ELinkIn, int ELinkPosIn, int XLinkIn, int XLinkPosIn, int TrackVectorPositionIn)
238  : TTrackElement(ElementIn), ELink(ELinkIn), ELinkPos(ELinkPosIn), XLink(XLinkIn), XLinkPos(XLinkPosIn), TrackVectorPosition(TrackVectorPositionIn),
239  CheckCount(9), IsARoute(false), AutoSignals(false), ConsecSignals(false)
240 {
241  if(!EntryExitNumber())
242  {
243  throw Exception("EXNumber failure in TPrefDirElement constructor");
244  }
247 }
248 
249 // ---------------------------------------------------------------------------
250 
251 AnsiString TPrefDirElement::LogPrefDir() const
252  // for debugging when passed as a call parameter
253 {
254  AnsiString LogString = "PthEl:-," + AnsiString(ELink) + "," + AnsiString(ELinkPos) + "," + AnsiString(XLink) + "," + AnsiString(XLinkPos) + "," +
255  AnsiString(EXNumber) + "," + AnsiString(TrackVectorPosition) + "," + AnsiString((short)AutoSignals) + "," + AnsiString((short)ConsecSignals) +
256  ",ElementID," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," + AnsiString(TrainIDOnBridgeTrackPos01) + "," +
257  AnsiString(TrainIDOnBridgeTrackPos23);
258 
259 // Track->TrackElementAt(73, TrackVectorPosition).LogTrack(12);
260  return LogString;
261 }
262 
263 // ---------------------------------------------------------------------------
264 
265 bool TPrefDirElement::EntryExitNumber() // true for valid number
266 /*
267  Computes a number corresponding to ELink & Xlink if set, or to the entry and exit link values for the track
268  at Link[0] and Link[1], or, if ELink or XLink not set, and a complex (4-entry) element, return false for error message.
269  This should be OK because only elements for which ELink & XLink not set are PrefDir/route start elements and leading points
270  as temporary end of PrefDir, and in both cases this function is not called as the direction is not displayed for these elements.
271  Uses simple links between any 2 entry & exit points for use in displaying PrefDir or route graphics, or original graphic during
272  route flashing. Should only be called when ELink & XLink set, or when ELinkPos & XLinkPos set deliberately from a
273  TTrackElement during route setting functions. If a bridge then an additional check is made in case the graphic needed
274  corresponds to an undebridge, i.e a gap needed between entry and exit. In this case the EXNumber is increased by
275  16 so as to be unique. Returns true if valid and sets EXNumber to the selected value.
276 */
277 
278 {
279  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EntryExitNumber");
280  int EXArray[16][2] =
281  {{4, 6}, {2, 8}, // horizontal & vertical
282  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
283  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
284  {1, 9}, {3, 7}}; // forward & reverse diagonals
285 
286  int EXNum = -1;
287  int Entry, Exit;
288 
289  if(ELink > -1)
290  Entry = ELink; // pick up simple elements even if ELink &/or XLink not set, as no ambiguity
291  else if(Link[2] == -1)
292  Entry = Link[0];
293  else
294  {
295  Utilities->CallLogPop(122);
296  return false;
297  }
298  if(XLink > -1)
299  Exit = XLink;
300  else if(Link[2] == -1)
301  Exit = Link[1];
302  else
303  {
304  Utilities->CallLogPop(123);
305  return false;
306  }
307 
308  for(int x = 0; x < 16; x++)
309  {
310  if((Entry == EXArray[x][0]) && (Exit == EXArray[x][1]) || (Entry == EXArray[x][1]) && (Exit == EXArray[x][0]))
311  {
312  EXNum = x;
313  }
314  }
315  if(EXNum == -1)
316  {
317  Utilities->CallLogPop(124);
318  return false;
319  }
320 
321  int BrNum = -1;
322 
323 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
324  the graphic for each of which is different because of the shape of the overbridge. The basic
325  entry/exit value is computed above, and this used to select only from elements with that entry/exit
326  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
327  int BrEXArray[24][2] = {
328  {4,6},{2,8},{1,9},{3,7},
329  {1,9},{3,7},{1,9},{3,7},
330  {2,8},{4,6},{2,8},{4,6}
331 */
332 
333  if(TrackType == Bridge)
334  {
335  if(EXNum == 1)
336  {
337  if(SpeedTag == 49)
338  BrNum = 1 + 16;
339  else if(SpeedTag == 54)
340  BrNum = 8 + 16;
341  else if(SpeedTag == 55)
342  BrNum = 10 + 16;
343  }
344  else if(EXNum == 0)
345  {
346  if(SpeedTag == 48)
347  BrNum = 0 + 16;
348  else if(SpeedTag == 58)
349  BrNum = 11 + 16;
350  else if(SpeedTag == 59)
351  BrNum = 9 + 16;
352  }
353  else if(EXNum == 14)
354  {
355  if(SpeedTag == 50)
356  BrNum = 2 + 16;
357  else if(SpeedTag == 52)
358  BrNum = 4 + 16;
359  else if(SpeedTag == 57)
360  BrNum = 6 + 16;
361  }
362  else if(EXNum == 15)
363  {
364  if(SpeedTag == 51)
365  BrNum = 3 + 16;
366  else if(SpeedTag == 53)
367  BrNum = 7 + 16;
368  else if(SpeedTag == 56)
369  BrNum = 5 + 16;
370  }
371  }
372  if(BrNum == -1)
373  EXNumber = EXNum;
374  else
375  EXNumber = BrNum;
376  Utilities->CallLogPop(125);
377  return true;
378 }
379 
380 // ---------------------------------------------------------------------------
381 
383 /*
384  This is the basic track graphic for use in plotting the original graphic during route flashing.
385  Enter with all set apart from EXGraphic & EntryDirectionGraphic
386 */
387 {
388  if(SpeedTag == 64)
389  return RailGraphics->LinkGraphicsPtr[16]; // intercept diagonal buffers
390 
391  if(SpeedTag == 65)
392  return RailGraphics->LinkGraphicsPtr[17];
393 
394  if(SpeedTag == 66)
395  return RailGraphics->LinkGraphicsPtr[18];
396 
397  if(SpeedTag == 67)
398  return RailGraphics->LinkGraphicsPtr[19];
399 
400  if(SpeedTag == 80)
401  return RailGraphics->LinkGraphicsPtr[20]; // intercept continuations
402 
403  if(SpeedTag == 81)
404  return RailGraphics->LinkGraphicsPtr[21];
405 
406  if(SpeedTag == 82)
407  return RailGraphics->LinkGraphicsPtr[22];
408 
409  if(SpeedTag == 83)
410  return RailGraphics->LinkGraphicsPtr[23];
411 
412  if(SpeedTag == 84)
413  return RailGraphics->LinkGraphicsPtr[24];
414 
415  if(SpeedTag == 85)
416  return RailGraphics->LinkGraphicsPtr[25];
417 
418  if(SpeedTag == 86)
419  return RailGraphics->LinkGraphicsPtr[26];
420 
421  if(SpeedTag == 87)
422  return RailGraphics->LinkGraphicsPtr[27];
423 
424  if(SpeedTag == 129)
425  return RailGraphics->LinkGraphicsPtr[28]; // intercept under footbridges
426 
427  if(SpeedTag == 130)
428  return RailGraphics->LinkGraphicsPtr[29];
429 
430  if(XLinkPos == -1) // not set, could be first element or last element = leading point
431  {
432 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or
433 // Points & don't want to display these)
434  if(Link[2] != -1)
435  return 0; // i.e. complex element, don't display
436  else
437  {
438  if(!EntryExitNumber())
439  {
440  throw Exception("Error in EntryExitNumber 4");
441  }
442  else
443  {
445  }
446  }
447  }
448  if(EXNumber > 15) // underbridge
449  {
451  }
452  else
453  {
455  }
456 }
457 
458 // ---------------------------------------------------------------------------
459 
461 /*
462  As above but for PrefDir graphics.
463 */
464 {
465  if(SpeedTag == 64)
466  return RailGraphics->LinkPrefDirGraphicsPtr[16]; // intercept diagonal buffers
467 
468  if(SpeedTag == 65)
470 
471  if(SpeedTag == 66)
473 
474  if(SpeedTag == 67)
476 
477  if(SpeedTag == 80)
478  return RailGraphics->LinkPrefDirGraphicsPtr[20]; // intercept continuations
479 
480  if(SpeedTag == 81)
482 
483  if(SpeedTag == 82)
485 
486  if(SpeedTag == 83)
488 
489  if(SpeedTag == 84)
491 
492  if(SpeedTag == 85)
494 
495  if(SpeedTag == 86)
497 
498  if(SpeedTag == 87)
500 
501  if(SpeedTag == 129)
502  return RailGraphics->LinkPrefDirGraphicsPtr[28]; // intercept under footbridges
503 
504  if(SpeedTag == 130)
506 
507  if(XLinkPos == -1) // not set, could be first element or last element = leading point
508  {
509 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
510  if(Link[2] != -1)
511  return 0; // i.e. complex element, don't display
512  else
513  {
514  if(!EntryExitNumber())
515  {
516  throw Exception("Error in EntryExitNumber 5");
517  }
518  else
520  }
521  }
522  if(EXNumber > 15) // underbridge
523  {
525  }
526  else
528 }
529 
530 // ---------------------------------------------------------------------------
531 
532 Graphics::TBitmap *TPrefDirElement::GetRouteGraphicPtr(bool AutoSigsFlag, bool ConsecSignalsRoute)
533 /*
534  As above but for route graphics.
535 */
536 {
537  if(!AutoSigsFlag && !ConsecSignalsRoute)
538  {
539  if(SpeedTag == 64)
540  return RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers
541 
542  if(SpeedTag == 65)
544 
545  if(SpeedTag == 66)
547 
548  if(SpeedTag == 67)
550 
551  if(SpeedTag == 80)
552  return RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations
553 
554  if(SpeedTag == 81)
556 
557  if(SpeedTag == 82)
559 
560  if(SpeedTag == 83)
562 
563  if(SpeedTag == 84)
565 
566  if(SpeedTag == 85)
568 
569  if(SpeedTag == 86)
571 
572  if(SpeedTag == 87)
574 
575  if(SpeedTag == 129)
576  return RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
577 
578  if(SpeedTag == 130)
580 
581  if(XLinkPos == -1) // not set, could be first element or last element = leading point
582  {
583  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
584  if(Link[2] != -1)
585  return 0; // i.e. complex element, don't display
586  else
587  {
588  if(!EntryExitNumber())
589  {
590  throw Exception("Error in EntryExitNumber 6");
591  }
592  else
594  }
595  }
596  if(EXNumber > 15) // underbridge
597  {
599  }
600  else
602  }
603 
604  else if(!AutoSigsFlag && ConsecSignalsRoute)
605  {
606  if(SpeedTag == 64)
607  return RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers
608 
609  if(SpeedTag == 65)
611 
612  if(SpeedTag == 66)
614 
615  if(SpeedTag == 67)
617 
618  if(SpeedTag == 80)
619  return RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations
620 
621  if(SpeedTag == 81)
623 
624  if(SpeedTag == 82)
626 
627  if(SpeedTag == 83)
629 
630  if(SpeedTag == 84)
632 
633  if(SpeedTag == 85)
635 
636  if(SpeedTag == 86)
638 
639  if(SpeedTag == 87)
641 
642  if(SpeedTag == 129)
643  return RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
644 
645  if(SpeedTag == 130)
647 
648  if(XLinkPos == -1) // not set, could be first element or last element = leading point
649  {
650  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
651  if(Link[2] != -1)
652  return 0; // i.e. complex element, don't display
653  else
654  {
655  if(!EntryExitNumber())
656  {
657  throw Exception("Error in EntryExitNumber 10");
658  }
659  else
661  }
662  }
663  if(EXNumber > 15) // underbridge
664  {
666  }
667  else
669  }
670 
671  else
672  {
673  if(SpeedTag == 64)
674  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers
675 
676  if(SpeedTag == 65)
678 
679  if(SpeedTag == 66)
681 
682  if(SpeedTag == 67)
684 
685  if(SpeedTag == 80)
686  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations
687 
688  if(SpeedTag == 81)
690 
691  if(SpeedTag == 82)
693 
694  if(SpeedTag == 83)
696 
697  if(SpeedTag == 84)
699 
700  if(SpeedTag == 85)
702 
703  if(SpeedTag == 86)
705 
706  if(SpeedTag == 87)
708 
709  if(SpeedTag == 129)
710  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
711 
712  if(SpeedTag == 130)
714 
715  if(XLinkPos == -1) // not set, could be first element or last element = leading point
716  {
717  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
718  if(Link[2] != -1)
719  return 0; // i.e. complex element, don't display
720  else
721  {
722  if(!EntryExitNumber())
723  {
724  throw Exception("Error in EntryExitNumber 11");
725  }
726  else
728  }
729  }
730  if(EXNumber > 15) // underbridge
731  {
733  }
734  else
736  }
737 }
738 
739 // ---------------------------------------------------------------------------
740 
742 /*
743  As above but for route flashing graphics. (Disused - now combined with above)
744 */
745 {
746  if(SpeedTag == 64)
747  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers
748 
749  if(SpeedTag == 65)
751 
752  if(SpeedTag == 66)
754 
755  if(SpeedTag == 67)
757 
758  if(SpeedTag == 80)
759  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations
760 
761  if(SpeedTag == 81)
763 
764  if(SpeedTag == 82)
766 
767  if(SpeedTag == 83)
769 
770  if(SpeedTag == 84)
772 
773  if(SpeedTag == 85)
775 
776  if(SpeedTag == 86)
778 
779  if(SpeedTag == 87)
781 
782  if(SpeedTag == 129)
783  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
784 
785  if(SpeedTag == 130)
787 
788  if(XLinkPos == -1) // not set, could be first element or last element = leading point
789  {
790 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
791  if(Link[2] != -1)
792  return 0; // i.e. complex element, don't display
793  else
794  {
795  if(!EntryExitNumber())
796  {
797  throw Exception("Error in EntryExitNumber 7");
798  }
799  else
801  }
802  }
803  if(EXNumber > 15) // underbridge
804  {
806  }
807  else
809 }
810 
811 // ---------------------------------------------------------------------------
812 
814 /*
815  Get PrefDir direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
816 */
817 {
818  if((ELink > 0) && (ELink < 10) && (ELink != 5))
820  else
821  {
822  throw Exception("Error in EntryExitNumber 8");
823  }
824 }
825 
826 // ---------------------------------------------------------------------------
827 
828 Graphics::TBitmap *TPrefDirElement::GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool ConsecSignalsRoute) const
829 /*
830  Get route direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
831 */
832 {
833  if((ELink > 0) && (ELink < 10) && (ELink != 5))
834  {
835  if(!AutoSigsFlag && !ConsecSignalsRoute)
837  else if(!AutoSigsFlag && ConsecSignalsRoute)
839  else
841  }
842  else
843  {
844  throw Exception("Error in EntryExitNumber 9");
845  }
846 }
847 
848 // ---------------------------------------------------------------------------
849 
851 /*
852  Set == operator when TrackVectorPosition, ELink & XLink all same
853 */
854 {
855  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
856  return true;
857  else
858  return false;
859 }
860 
861 // ---------------------------------------------------------------------------
862 
864 /*
865  Set != operator when any of TrackVectorPosition, ELink or XLink different
866 */
867 {
868  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
869  return false;
870  else
871  return true;
872 }
873 
874 // ---------------------------------------------------------------------------
875 // Track functions
876 // ---------------------------------------------------------------------------
877 
878 // ---------------------------------------------------------------------------
879 
880 TTrack::TActiveLevelCrossing::TActiveLevelCrossing()
881 {
882  ConsecSignals = false;
883  ReducedTimePenalty = false;
884  BarrierState = Up;
885  ChangeDuration = 0.0;
887  HLoc = 0;
888  VLoc = 0;
889  StartTime = TDateTime(0);
890 }
891 
892 // ---------------------------------------------------------------------------
893 
895 {
896 // CurrentSpeedButtonTag = 0; //not assigned yet
897 
898  HLocMin = 2000000000;
899  VLocMin = 2000000000;
900  HLocMax = -2000000000;
901  VLocMax = -2000000000;
902  SkipLocationNameMultiMapCheck = false; // new at v2.2.0, false is default value
903  CopyFlag = false; // only true for copying, so names aren't copied
904 
905  AnsiString NL = '\n';
906 
907  RouteFailMessage = "Unable to set a route:" + NL + NL + "it may be unreachable; " + NL + NL +
908  "reachable but with too many different directions leading away from the start point - set some points on the route required; " + NL + NL +
909  "blocked by a train, another route or a changing level crossing; " + NL + NL +
910  "or invalid - possibly due to a preferred direction mismatch or a missed signal in a green or blue route.";
911 
916 
917  int InternalLinkCheckArray[9][2] =
918  {{1, 9}, {4, 6}, {7, 3}, {2, 8}, {0, 0}, {8, 2}, {3, 7}, {6, 4}, {9, 1}};
919 
920 /* array of valid link values for 'old' location and 'new' location, where
921  array number = (((Hnew - Hold)+1)*3) + ((Vnew - Vold)+1) */
922 
923  for(int x = 0; x < 9; x++)
924  for(int y = 0; y < 2; y++)
925  LinkCheckArray[x][y] = InternalLinkCheckArray[x][y];
926 
927 // Platform and default track element values
928  TopPlatAllowed << 1 << 9 << 10 << 30 << 31 << 60 << 61 << 68 << 69 << 77 << 125 << 126 << 129 << 145;
929 // top & bot sigs, straights, straight points, buffers, signal, vert footcrossing, bot plat
930  BotPlatAllowed << 1 << 7 << 8 << 28 << 29 << 60 << 61 << 68 << 69 << 76 << 125 << 126 << 129 << 145;
931  LeftPlatAllowed << 2 << 12 << 14 << 33 << 35 << 62 << 63 << 70 << 71 << 79 << 127 << 128 << 130 << 146;
932  RightPlatAllowed << 2 << 11 << 13 << 32 << 34 << 62 << 63 << 70 << 71 << 78 << 127 << 128 << 130 << 146;
933  NameAllowed << 1 << 2 << 3 << 4 << 5 << 6 << 20 << 21 << 22 << 23 << 24 << 25 << 26 << 27 // disallow diagonals, points, crossovers, bridges, gaps,
934  << 60 << 61 << 62 << 63 << 68 << 69 << 70 << 71 << 80 << 81 << 82 << 83 << 125 << 126 << 127 << 128; // diag continuations, diag buffers, footcrossings (diagonals may be OK
935  // but as can't link diagonal locations would need solid blocks to allow linkage & that would look untidy except for single
936  // elements, & can always use straights so leave out.) Allow horiz & vert signals as from v2.6.0
937  LevelCrossingAllowed << 1 << 2; // only allow on straight tracks without direction markers
938 // Note platforms not allowed at continuations, but named non-station locations OK, though not allowed in timetables
939 
940  int HVArray[10][2] =
941  {{0, 0}, {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};
942 
943  for(int x = 0; x < 10; x++)
944  for(int y = 0; y < 2; y++)
945  LinkHVArray[x][y] = HVArray[x][y];
946  TrackFinished = false;
947 // DistancesSet = false;
948 
949  TSigElement TempSigTable[40] = // original four aspect
950  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
951  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
952 
955 
958 
959  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
960  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
961 
962  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
963  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
964  {75, 4, RailGraphics->gl75}};
965 
966  for(int x = 0; x < 40; x++)
967  {
968  SigTable[x] = TempSigTable[x];
969  }
970 
971  TSigElement TempSigTableThreeAspect[40] =
972  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
973  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
974 
977 
978  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
979  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
980 
981  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
982  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
983 
984  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
985  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
986  {75, 4, RailGraphics->gl75}};
987 
988  for(int x = 0; x < 40; x++)
989  {
990  SigTableThreeAspect[x] = TempSigTableThreeAspect[x];
991  }
992 
993  TSigElement TempSigTableTwoAspect[40] =
994  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
995  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
996 
997  {68, 1, RailGraphics->bm68green}, {69, 1, RailGraphics->bm69green}, {70, 1, RailGraphics->bm70green}, {71, 1, RailGraphics->bm71green},
998  {72, 1, RailGraphics->bm72green}, {73, 1, RailGraphics->bm73green}, {74, 1, RailGraphics->bm74green}, {75, 1, RailGraphics->bm75green},
999 
1000  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1001  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1002 
1003  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1004  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1005 
1006  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1007  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1008  {75, 4, RailGraphics->gl75}};
1009 
1010  for(int x = 0; x < 40; x++)
1011  {
1012  SigTableTwoAspect[x] = TempSigTableTwoAspect[x];
1013  }
1014 
1015  TSigElement TempSigTableGroundSignal[40] =
1019 
1023 
1027 
1031 
1032  {68, 4, RailGraphics->bm68grounddblred}, {69, 4, RailGraphics->bm69grounddblred}, // Attr 4 disused but leave in case re-instate
1035 
1036  for(int x = 0; x < 40; x++)
1037  {
1038  SigTableGroundSignal[x] = TempSigTableGroundSignal[x];
1039  }
1040 
1041 /*
1042  Named Location Arrays: Set out the adjacent positions and tracktypes that are accepted as valid connections for
1043  a single location. These are as follows:-
1044  Directly Adjacent = up, down, left or right - NOT diagonal.
1045  There are two separate groups, platforms, concourses & footcrossings (providing the crossing part touches or overlaps the other relevant
1046  named location) all link with each other providing directly adjacent, but not to NamedNonStationLocations.
1047  NamedNonStationLocation link to other NamedNonStationLocations providing directly adjacent, but not to anything else.
1048 
1049  //t 76
1050  //b 77
1051  //l 78
1052  //r 79
1053  //c 96
1054  //v fb 129
1055  //h fb 130
1056  //v underpass 145
1057  //h underpass 146
1058  //n 131
1059 */
1060 
1061  int Tag76[25][3] =
1062  {{-1, 0, 96}, // c top plat
1063  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1064  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1065  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {0, 0, 77}, {-1, 0, 78}, // l
1066  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1067  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, -1, 129}, // v fb
1068  {0, 0, 129}, {0, -1, 145}, // v up
1069  {0, 0, 145}};
1070 
1071  for(int x = 0; x < 25; x++)
1072  for(int y = 0; y < 3; y++)
1073  Tag76Array[x][y] = Tag76[x][y];
1074 
1075  int Tag77[25][3] =
1076  {{-1, 0, 96}, // c bot plat
1077  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1078  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {0, 0, 76}, {-1, 0, 77}, // b
1079  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1080  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1081  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1082  {0, 0, 129}, {0, 1, 145}, // v up
1083  {0, 0, 145}};
1084 
1085  for(int x = 0; x < 25; x++)
1086  for(int y = 0; y < 3; y++)
1087  Tag77Array[x][y] = Tag77[x][y];
1088 
1089  int Tag78[25][3] =
1090  {{-1, 0, 96}, // c left plat
1091  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1092  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1093  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1094  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1095  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 0, 79}, {-1, 0, 130}, // h fb
1096  {0, 0, 130}, {-1, 0, 146}, // h up
1097  {0, 0, 146}};
1098 
1099  for(int x = 0; x < 25; x++)
1100  for(int y = 0; y < 3; y++)
1101  Tag78Array[x][y] = Tag78[x][y];
1102 
1103  int Tag79[25][3] =
1104  {{-1, 0, 96}, // c right plat
1105  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1106  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1107  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1108  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {0, 0, 78}, {-1, 0, 79}, // r
1109  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {1, 0, 130}, // h fb
1110  {0, 0, 130}, {1, 0, 146}, // h up
1111  {0, 0, 146}};
1112 
1113  for(int x = 0; x < 25; x++)
1114  for(int y = 0; y < 3; y++)
1115  Tag79Array[x][y] = Tag79[x][y];
1116 
1117  int Tag96[28][3] =
1118  {{-1, 0, 96}, // c //concourse
1119  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1120  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1121  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1122  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1123  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1124  {0, -1, 129}, {1, 0, 130}, // h fb
1125  {-1, 0, 130}, {0, 1, 145}, // v up
1126  {0, -1, 145}, {1, 0, 146}, // h up
1127  {-1, 0, 146}};
1128 
1129  for(int x = 0; x < 28; x++)
1130  for(int y = 0; y < 3; y++)
1131  Tag96Array[x][y] = Tag96[x][y];
1132 
1133  int Tag129[8][3] = // vert fb
1134  {{0, -1, 96}, // c
1135  {0, -1, 77}, // b
1136  {0, -1, 129}, // v fb
1137 
1138  {0, 1, 96}, // c
1139  {0, 1, 76}, // t
1140  {0, 1, 129}, // v fb
1141 
1142  {0, 0, 76}, // t
1143  {0, 0, 77}}; // b
1144 
1145  for(int x = 0; x < 8; x++)
1146  for(int y = 0; y < 3; y++)
1147  Tag129Array[x][y] = Tag129[x][y];
1148 
1149  int Tag145[8][3] = // vert up
1150  {{0, -1, 96}, // c
1151  {0, -1, 77}, // b
1152  {0, -1, 145}, // v fb
1153 
1154  {0, 1, 96}, // c
1155  {0, 1, 76}, // t
1156  {0, 1, 145}, // v fb
1157 
1158  {0, 0, 76}, // t
1159  {0, 0, 77}}; // b
1160 
1161  for(int x = 0; x < 8; x++)
1162  for(int y = 0; y < 3; y++)
1163  Tag145Array[x][y] = Tag145[x][y];
1164 
1165  int Tag130[8][3] = // hor fb
1166  {{-1, 0, 96}, // c
1167  {-1, 0, 79}, // r
1168  {-1, 0, 130}, // h fb
1169 
1170  {1, 0, 96}, // c
1171  {1, 0, 78}, // l
1172  {1, 0, 130}, // h fb
1173 
1174  {0, 0, 78}, // l
1175  {0, 0, 79}}; // r
1176 
1177  for(int x = 0; x < 8; x++)
1178  for(int y = 0; y < 3; y++)
1179  Tag130Array[x][y] = Tag130[x][y];
1180 
1181  int Tag146[8][3] = // hor up
1182  {{-1, 0, 96}, // c
1183  {-1, 0, 79}, // r
1184  {-1, 0, 146}, // h fb
1185 
1186  {1, 0, 96}, // c
1187  {1, 0, 78}, // l
1188  {1, 0, 146}, // h fb
1189 
1190  {0, 0, 78}, // l
1191  {0, 0, 79}}; // r
1192 
1193  for(int x = 0; x < 8; x++)
1194  for(int y = 0; y < 3; y++)
1195  Tag146Array[x][y] = Tag146[x][y];
1196 
1197  int Tag131[4][3] =
1198  {{-1, 0, 131}, // n
1199  {1, 0, 131}, {0, -1, 131}, {0, 1, 131}};
1200 
1201  for(int x = 0; x < 4; x++)
1202  for(int y = 0; y < 3; y++)
1203  Tag131Array[x][y] = Tag131[x][y];
1204 
1205  int InternalFlipArray[FirstUnusedSpeedTagNumber] =
1206  {0, 1, 2, 5, 6, 3, 4, 9, 10, 7, 8, 13, 14, 11, 12, 15, 16, 17, 19, 18, 22, 23, 20, 21, 26, 27, 24, 25, 30, 31, 28, 29, 34, 35, 32, 33, 38, 39, 36, 37, 42,
1207  43, 40, 41, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 60, 61, 63, 62, 66, 67, 64, 65, 68, 69, 71, 70, 74, 75, 72, 73, 77, 76, 78,
1208  79, 80, 81, 83, 82, 86, 87, 84, 85, 88, 89, 91, 90, 94, 95, 92, 93, 96, 99, 100, 97, 98, 103, 104, 101, 102, 106, 105, 109, 110, 107, 108, 113, 114,
1209  111, 112, 117, 118, 115, 116, 119, 120, 121, 123, 122, 124, 125, 126, 128, 127, 129, 130, 131, 134, 133, 132, 135, 139, 138, 137, 136, 143, 142, 141,
1210  140, 144, 145, 146};
1211 
1212  int InternalMirrorArray[FirstUnusedSpeedTagNumber] =
1213  {0, 1, 2, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 15, 16, 17, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30, 33, 32, 35, 34, 37, 36, 39, 38, 41,
1214  40, 43, 42, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 61, 60, 62, 63, 65, 64, 67, 66, 69, 68, 70, 71, 73, 72, 75, 74, 76, 77, 79,
1215  78, 81, 80, 82, 83, 85, 84, 87, 86, 89, 88, 90, 91, 93, 92, 95, 94, 96, 98, 97, 100, 99, 102, 101, 104, 103, 106, 105, 108, 107, 110, 109, 112, 111,
1216  114, 113, 116, 115, 118, 117, 119, 120, 124, 122, 123, 121, 126, 125, 127, 128, 129, 130, 131, 132, 135, 134, 133, 137, 136, 139, 138, 142, 143, 140,
1217  141, 144, 145, 146};
1218 
1219  int InternalRotRightArray[FirstUnusedSpeedTagNumber] =
1220  {0, 2, 1, 4, 6, 3, 5, 14, 12, 13, 11, 7, 9, 8, 10, 15, 16, 17, 19, 18, 25, 27, 24, 26, 21, 23, 20, 22, 35, 33, 34, 32, 28, 30, 29, 31, 41, 43, 40, 42, 37,
1221  39, 36, 38, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 63, 62, 60, 61, 65, 67, 64, 66, 71, 70, 68, 69, 73, 75, 72, 74, 79, 78, 76,
1222  77, 83, 82, 80, 81, 85, 87, 84, 86, 91, 90, 88, 89, 93, 95, 92, 94, 96, 102, 104, 101, 103, 98, 100, 97, 99, 106, 105, 108, 110, 107, 109, 116, 118,
1223  115, 117, 112, 114, 111, 113, 120, 119, 122, 124, 121, 123, 127, 128, 126, 125, 130, 129, 131, 133, 134, 135, 132, 137, 138, 139, 136, 143, 142, 140,
1224  141, 144, 146, 145};
1225 
1226  int InternalRotLeftArray[FirstUnusedSpeedTagNumber] =
1227  {0, 2, 1, 5, 3, 6, 4, 11, 13, 12, 14, 10, 8, 9, 7, 15, 16, 17, 19, 18, 26, 24, 27, 25, 22, 20, 23, 21, 32, 34, 33, 35, 31, 29, 30, 28, 42, 40, 43, 41, 38,
1228  36, 39, 37, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 62, 63, 61, 60, 66, 64, 67, 65, 70, 71, 69, 68, 74, 72, 75, 73, 78, 79, 77,
1229  76, 82, 83, 81, 80, 86, 84, 87, 85, 90, 91, 89, 88, 94, 92, 95, 93, 96, 103, 101, 104, 102, 99, 97, 100, 98, 106, 105, 109, 107, 110, 108, 117, 115,
1230  118, 116, 113, 111, 114, 112, 120, 119, 123, 121, 124, 122, 128, 127, 125, 126, 130, 129, 131, 135, 132, 133, 134, 139, 136, 137, 138, 142, 143, 141,
1231  140, 144, 146, 145};
1232 
1233  for(int x = 0; x < FirstUnusedSpeedTagNumber; x++)
1234  {
1235  FlipArray[x] = InternalFlipArray[x];
1236  MirrorArray[x] = InternalMirrorArray[x];
1237  RotRightArray[x] = InternalRotRightArray[x];
1238  RotLeftArray[x] = InternalRotLeftArray[x];
1239  }
1240 }
1241 
1242 // ---------------------------------------------------------------------------
1244 {
1245 // delete TrackVectorPtr;
1246 // delete FixedTrackArrayPtr;
1247  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1248 
1249  while(UGMIt != Track->UserGraphicMap.end()) // delete all the TPictures in the map
1250  {
1251  delete UGMIt->second;
1252  UGMIt++;
1253  }
1254  delete GapFlashGreen;
1255  delete GapFlashRed;
1256  // all the rest are cleared by the relevant automatic destructors
1257 }
1258 
1259 // ---------------------------------------------------------------------------
1260 
1262 {
1263  Graphics::TBitmap *TrackImageArray[FirstUnusedSpeedTagNumber] =
1264  {
1265 // loc 0 not used, set to bmSolidBgnd
1269 // no 17 not used (was used for text in early phases), set to bmSolidBgnd
1289 
1290  Graphics::TBitmap *SmallTrackImageArray[FirstUnusedSpeedTagNumber] =
1291  {
1292 // loc 0 not used, set to smSolidBgnd
1296 // no 17 not used (was used for text in early phases), set to smSolidBgnd
1315  RailGraphics->smTransparent, RailGraphics->sm129, RailGraphics->sm130 // use small footbridges for underpasses
1316  };
1317 
1318 // track types
1319  TTrackType TrackTypeArray[FirstUnusedSpeedTagNumber] =
1320  {Erase, // 1 0
1321  Simple, Simple, Simple, Simple, Simple, Simple, // 6 1-6
1322  Points, Points, Points, Points, Points, Points, Points, Points, // 8 7-14
1323  Crossover, Crossover, // 2 15-16
1324  Unused, // 17 (was for text in earlier development) //1 17
1327  Crossover, Crossover, Crossover, Crossover, // 4 44-47
1331  Platform, Platform, Platform, Platform, // 4 76-79
1334  Concourse, // 1 96
1337  Simple, Simple, Simple, Simple, // 4 125-128
1338  FootCrossing, FootCrossing, // 2 129-130
1339  NamedNonStationLocation, // 1 131
1340  Points, Points, Points, Points, Points, Points, Points, Points, // 8 132-139
1341  Simple, Simple, Simple, Simple, // 4 140-143
1342  LevelCrossing, // 1 144
1343  FootCrossing, FootCrossing // 2 145 & 146
1344  };
1345 
1346 // links
1347  int Links[FirstUnusedSpeedTagNumber][4] =
1348  {{-1, -1, -1, -1}, // erase element
1349  {4, 6, -1, -1}, {2, 8, -1, -1}, {6, 8, -1, -1}, {4, 8, -1, -1}, {2, 6, -1, -1}, {2, 4, -1, -1}, // simple
1350  {4, 6, 4, 2}, {6, 4, 6, 2}, {4, 6, 4, 8}, {6, 4, 6, 8}, {8, 2, 8, 4}, {8, 2, 8, 6}, {2, 8, 2, 4}, {2, 8, 2, 6}, // points
1351 // points always have links 0 & 2 = lead, link 1 = trailing straight, link 3 = trailing diverging
1352  {4, 6, 2, 8}, {1, 9, 3, 7}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1353  {-1, -1, -1, -1}, // unused
1354  {3, 7, -1, -1}, {1, 9, -1, -1}, {7, 6, -1, -1}, {4, 9, -1, -1}, {1, 6, -1, -1}, {4, 3, -1, -1}, {3, 8, -1, -1}, {1, 8, -1, -1}, {2, 9, -1, -1},
1355  {2, 7, -1, -1}, // simple
1356  {4, 6, 4, 3}, {6, 4, 6, 1}, {4, 6, 4, 9}, {6, 4, 6, 7}, {8, 2, 8, 1}, {8, 2, 8, 3}, {2, 8, 2, 7}, {2, 8, 2, 9}, {9, 1, 9, 2}, {7, 3, 7, 2}, {3, 7, 3, 8
1357  }, {1, 9, 1, 8}, {9, 1, 9, 4}, {7, 3, 7, 6}, {3, 7, 3, 4}, {1, 9, 1, 6}, // points
1358 // points always have links 0 & 2 = lead, link 1 = trailing straight (or left diverging if no straight), link 3 = trailing diverging
1359 // (or right diverging if no straight)
1360  {1, 9, 2, 8}, {2, 8, 3, 7}, {4, 6, 3, 7}, {1, 9, 4, 6}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1361  {2, 8, 4, 6}, {4, 6, 2, 8}, {3, 7, 1, 9}, {1, 9, 3, 7}, {2, 8, 1, 9}, {2, 8, 3, 7}, {3, 7, 2, 8}, {1, 9, 2, 8}, {4, 6, 3, 7}, {4, 6, 1, 9}, {1, 9, 4, 6
1362  }, {3, 7, 4, 6}, // bridge, links 2 & 3 = underbridge
1363  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1
1364  }, // buffers - position 0 = buffer
1365  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1
1366  }, // signals (need Config to determine signal end, see below)
1367  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // platform
1368  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1
1369  }, // continuation - position 0 = continuation
1370  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1
1371  }, // gapjump - position 0 = gap
1372  {-1, -1, -1, -1}, // Concourse
1373  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1374  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1375  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1376  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // Parapets
1377  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, // arrows
1378  {4, 6, -1, -1}, {2, 8, -1, -1}, // footbridges
1379  {-1, -1, -1, -1}, // NamedNonStationLocation
1380  {8, 1, 8, 3}, {4, 3, 4, 9}, {2, 9, 2, 7}, {6, 7, 6, 1}, {9, 4, 9, 2}, {7, 2, 7, 6}, {1, 6, 1, 8}, {3, 8, 3, 4}, // points without straight legs
1381 // these points have links 0 & 2 = lead, link 1 = LH trailing, link 3 = RH trailing
1382  {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, {1, 9, -1, -1}, // arrowed diagonals
1383  {-1, -1, -1, -1}, // level crossing
1384  {4, 6, -1, -1}, {2, 8, -1, -1}, // underpasses/surface crossings
1385  };
1386 
1388  {{NotSet, NotSet, NotSet, NotSet}, // unused
1392  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1394  {NotSet, NotSet, NotSet, NotSet}, // unused
1398  {Connection, Connection, NotSet, NotSet}, // simple
1402  {Lead, Trail, Lead, Trail}, // points
1404  {CrossConn, CrossConn, CrossConn, CrossConn}, // crossover
1413  }, // signals (signal at exit end in forward direction)
1417  }, // continuation
1420  {NotSet, NotSet, NotSet, NotSet}, // Concourse
1429  {Connection, Connection, NotSet, NotSet}, // Arrows
1431  {NotSet, NotSet, NotSet, NotSet}, // NamedNonStationLocation
1433  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1435  {Connection, Connection, NotSet, NotSet}, // Arrowed diagonals
1436  {NotSet, NotSet, NotSet, NotSet}, // Level crossing
1437  {Connection, Connection, NotSet, NotSet}, {Connection, Connection, NotSet, NotSet} // Underpasses/surface crossings
1438  };
1439 
1440  for(int x = 0; x < 17; x++)
1441  {
1442  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1443  }
1444  FixedTrackPiece[17] = TFixedTrackPiece(17, TrackTypeArray[17], Links[17], Configs[17], 0, 0);
1445 // 17 was the old text value so don't want any graphics (now disused)
1446  for(int x = 18; x < FirstUnusedSpeedTagNumber; x++)
1447  {
1448  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1449  }
1450 }
1451 
1452 // ---------------------------------------------------------------------------
1453 TGraphicElement::TGraphicElement(): OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1454  ExistingGraphicLoaded(false), Width(16), Height(16)
1455 {
1456  OriginalGraphic = new Graphics::TBitmap;
1457  OriginalGraphic->PixelFormat = pf8bit;
1458  OriginalGraphic->Width = Width;
1459  OriginalGraphic->Height = Height;
1460  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1461 }
1462 
1463 // ---------------------------------------------------------------------------
1464 
1465 TGraphicElement::TGraphicElement(int WidthIn, int HeightIn): OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1466  ExistingGraphicLoaded(false), Width(WidthIn), Height(HeightIn)
1467 {
1468  OriginalGraphic = new Graphics::TBitmap;
1469  OriginalGraphic->PixelFormat = pf8bit;
1470  OriginalGraphic->Width = Width;
1471  OriginalGraphic->Height = Height;
1472  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1473 }
1474 
1475 // ---------------------------------------------------------------------------
1476 
1478 {
1479  delete OriginalGraphic;
1480 }
1481 
1482 // ---------------------------------------------------------------------------
1483 
1484 void TGraphicElement::SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
1485 {
1486  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetScreenHVSource," + AnsiString(HPosIn) + "," + AnsiString(VPosIn));
1487  HPos = HPosIn; // HPos & VPos are members of TGraphicElement
1488  VPos = VPosIn;
1489  int Left, Top; // can't use e.g. PointFlash.SourceRect.Left & Top directly as references as don't exist as objects in their own right
1490 
1491  Track->GetScreenPositionsFromTruePos(2, Left, Top, HPos, VPos);
1492  SourceRect.init(Left, Top, Left + Width, Top + Height);
1493  ScreenSourceSet = true;
1494  Utilities->CallLogPop(422);
1495 }
1496 
1497 // ---------------------------------------------------------------------------
1498 
1500 {
1501  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalScreenGraphic");
1502  if(!OverlayLoaded)
1503  {
1504  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalScreenGraphic()");
1505  }
1506  if((OverlayGraphic->Width != 16) || (OverlayGraphic->Height != 16))
1507  {
1508  throw Exception("Overlay not 16x16 in TGraphicElement::LoadOriginalScreenGraphic()");
1509  }
1510  if(!ScreenSourceSet)
1511  {
1512  throw Exception("Source not set in TGraphicElement::LoadOriginalScreenGraphic()");
1513  }
1514  if(ExistingGraphicLoaded) // can only call one of the load functions
1515  {
1516  throw Exception("ExistingGraphicLoaded in TGraphicElement::LoadOriginalScreenGraphic()");
1517  }
1518  if(OverlayPlotted) // don't load from screen if overlay plotted
1519  {
1520  Utilities->CallLogPop(775);
1521  return;
1522  }
1523  TRect DestRect(0, 0, Width, Height);
1524 
1526  OriginalLoaded = true;
1527  ScreenGraphicLoaded = true;
1528  Utilities->CallLogPop(423);
1529 }
1530 
1531 // ---------------------------------------------------------------------------
1532 
1533 void TGraphicElement::LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
1534 /*
1535  Overrides size set in the constructor, SourceRect & HPos & VPos in SetScreenHVSource
1536 */
1537 {
1538  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalExistingGraphic," + AnsiString(HOffset) + "," +
1539  AnsiString(VOffset) + "," + AnsiString(WidthIn) + "," + AnsiString(HeightIn));
1540  if(!OverlayLoaded)
1541  {
1542  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalExistingGraphic()");
1543  }
1544  if(!ScreenSourceSet) // has to be called to set HPos & VPos
1545  {
1546  throw Exception("Source not set in TGraphicElement::LoadOriginalExistingGraphic()");
1547  }
1548  if(ScreenGraphicLoaded) // can only call one of the load functions
1549  {
1550  throw Exception("ScreenGraphicLoaded in TGraphicElement::LoadOriginalExistingGraphic()");
1551  }
1552  Width = WidthIn;
1553  Height = HeightIn;
1554  OriginalGraphic->Width = Width;
1555  OriginalGraphic->Height = Height;
1556  HPos += HOffset; // originally set in SetScreenHVSource to position of H & V locations
1557  VPos += VOffset;
1558  TRect DestRect(0, 0, Width, Height);
1559 
1560  SourceRect.init(HOffset, VOffset, HOffset + Width, VOffset + Height);
1561  OriginalGraphic->Canvas->CopyRect(DestRect, Graphic->Canvas, SourceRect);
1562  OriginalLoaded = true;
1563  ExistingGraphicLoaded = true;
1564  Utilities->CallLogPop(424);
1565 }
1566 
1567 // ---------------------------------------------------------------------------
1568 
1569 void TGraphicElement::LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
1570 {
1571  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOverlayGraphic,");
1572  OverlayGraphic = Overlay;
1573  OverlayLoaded = true;
1574  Utilities->CallLogPop(425);
1575 }
1576 
1577 // ---------------------------------------------------------------------------
1578 
1580 {
1581  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOverlay,");
1582  if(!OverlayLoaded)
1583  {
1584  throw Exception("Overlay not loaded in TGraphicElement::PlotOverlay()");
1585  }
1586  if(!OverlayPlotted)
1587  {
1588  Disp->PlotOutput(35, HPos, VPos, OverlayGraphic); // plot overlay
1589  Disp->Update();
1590  OverlayPlotted = true;
1591  }
1592  Utilities->CallLogPop(426);
1593 }
1594 
1595 // ---------------------------------------------------------------------------
1596 
1598 {
1599  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOriginal,");
1600  if(OverlayPlotted)
1601  {
1602  if(!OriginalLoaded) // this comes after OverlayPlotted because may wish to 'try' to plot original even
1603  // when it isn't loaded in case it had been plotted - e.g. when change user modes
1604  {
1605  throw Exception("Original not loaded in TGraphicElement::PlotOriginal()");
1606  }
1607  Disp->PlotOutput(36, HPos, VPos, OriginalGraphic); // replot original
1608  Disp->Update(); // This was commented out originally but when in flashes much less frequent when points changing manually
1609  OverlayPlotted = false;
1610  }
1611  Utilities->CallLogPop(427);
1612 }
1613 
1614 // ---------------------------------------------------------------------------
1615 
1617 {
1618  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoTrack");
1619  bool TrackPresent = false;
1620 
1621  if(InactiveTrackVector.size() != 0)
1622  {
1623  Utilities->CallLogPop(1333);
1624  return false;
1625  }
1626  else if(TrackVector.size() == 0)
1627  {
1628  Utilities->CallLogPop(1334);
1629  return true;
1630  }
1631  else
1632  {
1633  for(unsigned int x = 0; x < TrackVector.size(); x++)
1634  {
1635  if((TrackVector.at(x).SpeedTag != 0))
1636  TrackPresent = true;
1637  }
1638  }
1639  Utilities->CallLogPop(1335);
1640  return !TrackPresent;
1641 }
1642 
1643 // ---------------------------------------------------------------------------
1644 
1645 bool TTrack::NoActiveTrack(int Caller)
1646 {
1647  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoActiveTrack");
1648  bool TrackPresent = false;
1649 
1650  if(TrackVector.size() == 0)
1651  {
1652  Utilities->CallLogPop(1582);
1653  return true;
1654  }
1655  else
1656  {
1657  for(unsigned int x = 0; x < TrackVector.size(); x++)
1658  {
1659  if((TrackVector.at(x).SpeedTag != 0))
1660  TrackPresent = true;
1661  break;
1662  }
1663  }
1664  Utilities->CallLogPop(1583);
1665  return !TrackPresent;
1666 }
1667 
1668 // ---------------------------------------------------------------------------
1669 
1670 void TTrack::EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
1671 {
1672  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseTrackElement," + AnsiString(HLocInput) + "," +
1673  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
1674  TrackEraseSuccessfulFlag = false;
1675 // TrackEraseSuccessfulFlag used for both track element and inactive element erase,
1676 // since have to match platforms as well as track
1677 // used to set TrackFinished to false if an element erased
1678 
1679  ErasedTrackVectorPosition = -1; // marker for no element erased
1680  AnsiString SName = "", ErrorString;
1682  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
1683  TTrackMapIterator TrackMapPtr;
1684  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
1685 
1686  if(TrackVector.size() != 0)
1687  {
1688  TrackMapKeyPair.first = HLocInput;
1689  TrackMapKeyPair.second = VLocInput;
1690  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
1691  if(TrackMapPtr != TrackMap.end())
1692  {
1693  bool FoundFlag;
1694  int VecPos = GetVectorPositionFromTrackMap(37, HLocInput, VLocInput, FoundFlag);
1695  if(FoundFlag) // should find it as it's in the map
1696  {
1697  if(TrackElementAt(629, VecPos).FixedNamedLocationElement) // footcrossings only
1698  {
1699  SName = TrackElementAt(1, VecPos).LocationName;
1700  SNIt = FindNamedElementInLocationNameMultiMap(7, SName, TrackVector.begin() + VecPos, ErrorString);
1701  if(ErrorString != "")
1702  {
1703  throw Exception(ErrorString + " for EraseTrackElement 1");
1704  }
1705  LocationNameMultiMap.erase(SNIt);
1706  }
1707 
1708  TrackVector.erase(TrackVector.begin() + TrackMapPtr->second);
1709  // ensure erase vector element before map element as iterator no longer valid after a map erase
1710  TrackMap.erase(TrackMapPtr);
1711  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(2, HLocInput, VLocInput); // plot a blank element
1712  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
1714  ResetAnyNonMatchingGaps(1); // in case the deleted element was a set gap
1715  if(SName != "")
1716  {
1717  EraseLocationAndActiveTrackElementNames(5, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
1718  int HPos, VPos;
1719  if(TextHandler->FindText(1, SName, HPos, VPos))
1720  {
1721  if(TextHandler->TextErase(5, HPos, VPos, SName))
1722  {;
1723  } // condition not used
1724  }
1725  }
1726  ErasedTrackVectorPosition = VecPos;
1727  TrackEraseSuccessfulFlag = true;
1728  }
1729  }
1730  }
1731 
1732  if(InactiveTrackVector.size() != 0)
1733  {
1734  unsigned int VecPos;
1735  InactiveTrackMapKeyPair.first = HLocInput;
1736  InactiveTrackMapKeyPair.second = VLocInput;
1737  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair);
1738  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
1739  {
1740  SName = "";
1741  VecPos = InactiveTrack2MultiMapIterator->second;
1742  if(InactiveTrackElementAt(0, VecPos).FixedNamedLocationElement)
1743  {
1744  SName = InactiveTrackElementAt(1, VecPos).LocationName;
1745  SNIt = FindNamedElementInLocationNameMultiMap(2, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
1746  if(ErrorString != "")
1747  {
1748  throw Exception(ErrorString + " for EraseTrackElement 2A");
1749  }
1750  LocationNameMultiMap.erase(SNIt);
1751  }
1752  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
1753  // ensure erase vector element before map element as iterator no longer valid after a map erase
1754  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
1755  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(1, HLocInput, VLocInput); // plot a blank element
1756  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
1758  TrackEraseSuccessfulFlag = true;
1759  if(SName != "")
1760  {
1761  EraseLocationAndActiveTrackElementNames(3, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
1762  int HPos, VPos;
1763  if(TextHandler->FindText(2, SName, HPos, VPos))
1764  {
1765  if(TextHandler->TextErase(6, HPos, VPos, SName))
1766  {;
1767  } // condition not used
1768  }
1769  }
1770  }
1771 
1772  if(InactiveTrackVector.size() != 0) // need to check again as last access may have erased the last element
1773  {
1774  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // may be up to 2 elements (platforms) at same location
1775  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
1776  {
1777  SName = "";
1778  VecPos = InactiveTrack2MultiMapIterator->second;
1779  if(InactiveTrackElementAt(2, VecPos).FixedNamedLocationElement)
1780  {
1781  SName = InactiveTrackElementAt(3, VecPos).LocationName;
1782  SNIt = FindNamedElementInLocationNameMultiMap(3, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
1783  if(ErrorString != "")
1784  {
1785  throw Exception(ErrorString + " for EraseTrackElement 2B");
1786  }
1787  LocationNameMultiMap.erase(SNIt);
1788  }
1789  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
1790  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
1791  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
1793  if(SName != "")
1794  {
1795  EraseLocationAndActiveTrackElementNames(4, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
1796  int HPos, VPos;
1797  if(TextHandler->FindText(3, SName, HPos, VPos))
1798  {
1799  if(TextHandler->TextErase(7, HPos, VPos, SName))
1800  {;
1801  } // condition not used
1802  }
1803  }
1804  }
1805  }
1806  }
1807  if(TrackEraseSuccessfulFlag)
1808  {
1809  CalcHLocMinEtc(2);
1810  SetTrackFinished(false);
1811  }
1812  if(InternalChecks)
1813  {
1814  CheckMapAndTrack(1); // test
1815  CheckMapAndInactiveTrack(1); // test
1816  CheckLocationNameMultiMap(6); // test
1817  }
1818  Utilities->CallLogPop(428);
1819 }
1820 
1821 // ---------------------------------------------------------------------------
1822 
1823 void TTrack::PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
1824  // TrackLinkingRequiredFlag only relates to elements that require track linking after plotting - used to set TrackFinished
1825  // to false in calling function. New at v2.2.0 new parameter 'Aspect' to ensure signals plotted with correct number of aspects (for pasting)
1826  // and also when zero and combined with SignalPost to indicate that adding track rather than pasting
1827 {
1828  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotAndAddTrackElement," + AnsiString(CurrentTag) + "," +
1829  AnsiString(HLocInput) + "," + AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
1830  bool PlatAllowedFlag = false;
1831 
1832  TrackLinkingRequiredFlag = false;
1833 /*
1834  Not erase, that covered separately.
1835  First check if Current SpeedButton assigned, then check if a platform and only
1836  permit if an appropriate trackpiece already there & not a same platform there.
1837  - can't enter a platform without track first.
1838  Then for non-platforms, check if a track piece already present at location &
1839  reject if so.
1840 */
1841 
1842  TLocationNameMultiMapEntry LocationNameEntry;
1843 
1844  LocationNameEntry.first = "";
1845  if(CurrentTag == 0)
1846  {
1847  Utilities->CallLogPop(429);
1848  return; // not assigned yet
1849  }
1850 
1851  TTrackElement TempTrackElement(FixedTrackArray.FixedTrackPiece[CurrentTag]);
1852 
1853  TempTrackElement.HLoc = HLocInput;
1854  TempTrackElement.VLoc = VLocInput;
1855  SetElementID(1, TempTrackElement); // TempTrackElement is the one to be added
1856 // new at version 0.6 - set signal aspect depending on build mode
1857 
1858  if(TempTrackElement.TrackType == SignalPost)
1859  {
1860  if(Aspect == 0) // new at v2.2.0, '0' and SignalPost together means that track being added & not pasted, because when
1861  // pasting a SignalPost can only have values 1 to 4
1862  {
1864  {
1865  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
1866  }
1868  {
1869  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
1870  }
1872  {
1873  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
1874  }
1875  else
1876  {
1877  TempTrackElement.SigAspect = TTrackElement::FourAspect;
1878  }
1879  }
1880  else if(Aspect == 1)
1881  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
1882  else if(Aspect == 2)
1883  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
1884  else if(Aspect == 3)
1885  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
1886  else
1887  TempTrackElement.SigAspect = TTrackElement::FourAspect;
1888  }
1889 
1890  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
1891  int VecPos = GetVectorPositionFromTrackMap(12, HLocInput, VLocInput, FoundFlag); // active track already there
1892  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(5, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
1893  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
1894 
1895  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
1896  {
1898  NonStationOrLevelCrossingPresent = true;
1899  if(InactiveTrackElementAt(117, IMPair.first).TrackType == LevelCrossing)
1900  NonStationOrLevelCrossingPresent = true;
1901  if(InactiveTrackElementAt(5, IMPair.first).TrackType == Platform)
1902  PlatformPresent = true;
1903  // no need to check IMPair.second since if that exists it is because .first is a platform
1904  InactiveSpeedTag1 = InactiveTrackElementAt(6, IMPair.first).SpeedTag;
1905  InactiveSpeedTag2 = InactiveTrackElementAt(7, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
1906  }
1907 
1908 // check platforms
1909  if(TempTrackElement.TrackType == Platform)
1910  {
1911  if(FoundFlag) // active track element already there
1912  {
1913  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
1914  {;
1915  }
1916  // same platform type already there so above keeps PlatAllowedFlag false
1917  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
1918  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
1919  {
1920  PlatAllowedFlag = true;
1921  }
1922  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
1923  {
1924  PlatAllowedFlag = true;
1925  }
1926  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
1927  {
1928  PlatAllowedFlag = true;
1929  }
1930  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
1931  {
1932  PlatAllowedFlag = true;
1933  }
1934  if(PlatAllowedFlag)
1935  {
1936  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
1937  TrackPush(1, TempTrackElement);
1938  SearchForAndUpdateLocationName(1, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
1939  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
1940  // Must be called AFTER TrackPush
1941  // No need to plot the element - Clearand ... called after this function called
1942  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
1943  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
1944 // drop in v2.4.0 if(TrackElementAt(2, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
1945 // AnsiString(TrackElementAt(3, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
1946 // TrackElementAt(4, VecPos).Length01 = DefaultTrackLength;
1947  if(InternalChecks)
1948  {
1949  CheckMapAndInactiveTrack(5); // test
1950  CheckLocationNameMultiMap(4); // test
1951  }
1952  Utilities->CallLogPop(430);
1953  return;
1954  }
1955  } // if(FoundFlag)
1956  Utilities->CallLogPop(431);
1957  return;
1958  } // if platform
1959 
1960 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
1961  if(TempTrackElement.TrackType == NamedNonStationLocation)
1962  {
1963  if((FoundFlag && (NameAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
1964  (!FoundFlag && !InactiveFoundFlag))
1965  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
1966  {
1967  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
1968  TrackPush(2, TempTrackElement);
1969  SearchForAndUpdateLocationName(2, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
1970  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
1971  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
1972  {
1973 // drop in v2.4.0 if(TrackElementAt(830, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
1974 // AnsiString(TrackElementAt(831, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
1975 // TrackElementAt(832, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
1976  }
1977  if(InternalChecks)
1978  {
1979  CheckMapAndInactiveTrack(11); // test
1980  CheckLocationNameMultiMap(12); // test
1981  }
1982  Utilities->CallLogPop(432);
1983  return;
1984  }
1985  else
1986  {
1987  Utilities->CallLogPop(433);
1988  return;
1989  }
1990  }
1991 
1992 // check if a level crossing - OK if placed on a plain straight track
1993  if(TempTrackElement.TrackType == LevelCrossing)
1994  {
1995  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
1996  {
1997  TrackPush(11, TempTrackElement);
1998  PlotRaisedLinkedLevelCrossingBarriers(0, TrackVector.at(VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
1999 // no need for reference to LC element as can't be open
2000  TrackLinkingRequiredFlag = true;
2001  Utilities->CallLogPop(1907);
2002  return;
2003  }
2004  else
2005  {
2006  Utilities->CallLogPop(1906);
2007  return; // was a level crossing but can't place it for some reason
2008  }
2009  }
2010 
2011 // check if another element already there
2012  else if(FoundFlag || InactiveFoundFlag)
2013  {
2014  Utilities->CallLogPop(434);
2015  return; // something already there (active or inactive track)
2016  }
2017 
2018 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2019 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2020 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2021 // do this after pushed into vector so that can use EnterLocationName
2022 
2023  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2024  {
2025  TrackPush(3, TempTrackElement);
2026  SearchForAndUpdateLocationName(3, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2027  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2028  }
2029  else if(TempTrackElement.TrackType == Points)
2030  {
2031  TrackPush(4, TempTrackElement);
2032  bool BothPointFillets = true;
2033  PlotPoints(6, TempTrackElement, Display, BothPointFillets);
2034  }
2035  else if(TempTrackElement.TrackType == SignalPost)
2036  {
2037  TrackPush(10, TempTrackElement);
2038  PlotSignal(12, TempTrackElement, Display);
2039  }
2040  else
2041  {
2042  TrackPush(5, TempTrackElement);
2043  TempTrackElement.PlotVariableTrackElement(1, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2044  }
2045  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2046  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2047  if(InternalChecks)
2048  {
2049  CheckMapAndTrack(2); // test
2050  CheckMapAndInactiveTrack(2); // test
2051  CheckLocationNameMultiMap(5); // test
2052  }
2053  Utilities->CallLogPop(2062);
2054 }
2055 
2056 // ---------------------------------------------------------------------------
2057 
2058 void TTrack::PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag,
2059  bool InternalChecks)
2060  // new at v2.2.0 - similar to above but keeping speed & length attributes (for pasting) and also pastes location names
2061  // NB experimental: - need to change all caller numbers & check thoroughly if release
2062  // as is if single elements have location or platform names then have message that names fail to align when mouse over
2063  // need to deal with this if release - it's because ActiveTrackElementName is cleared in the new function, if not a single element
2064  // then set when call SearchForAndUpdateLocationName. Maybe instead of clearing can set to the InactiveTrackElementName at the same location?
2065 {
2066  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPastedTrackElementWithAttributes," + AnsiString(HLocInput) + "," +
2067  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2068  bool PlatAllowedFlag = false;
2069 
2070  TrackLinkingRequiredFlag = false;
2071 /*
2072  Not erase, that covered separately.
2073  First check if Current SpeedButton assigned, then check if a platform and only
2074  permit if an appropriate trackpiece already there & not a same platform there.
2075  - can't enter a platform without track first.
2076  Then for non-platforms, check if a track piece already present at location &
2077  reject if so.
2078 */
2079 
2080  TLocationNameMultiMapEntry LocationNameEntry;
2081 
2082  LocationNameEntry.first = "";
2083  if(TempTrackElement.SpeedTag == 0)
2084  {
2085  Utilities->CallLogPop(2063);
2086  return; // not assigned yet
2087  }
2088 
2089  TempTrackElement.HLoc = HLocInput;
2090  TempTrackElement.VLoc = VLocInput;
2091  for(int x = 0; x < 4; x++) // unset any gaps
2092  {
2093  if(TempTrackElement.Config[x] == Gap)
2094  TempTrackElement.ConnLinkPos[x] = -1;
2095  TempTrackElement.Conn[x] = -1;
2096  }
2097  SetElementID(5, TempTrackElement); // TempTrackElement is the one to be added
2098 // new at version 0.6 - set signal aspect depending on build mode
2099  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2100  int VecPos = GetVectorPositionFromTrackMap(56, HLocInput, VLocInput, FoundFlag); // active track already there
2101 
2102  // if find an active track element (as has been pasted into track vector when dealing with inactive elements in SelectVector)
2103  // )set its ActiveTrackElementName to same name as the inactive element (from SelectVector). Note that can't use LocationName
2104  // for the active track element because these aren't set
2105  // if don't do this then get a mismatch error during map checks later
2106 
2107  // if(FoundFlag) TrackElementAt(xx, VecPos).ActiveTrackElementName = TempTrackElement.LocationName; //doesn't work!!
2108 
2109  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(26, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2110  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2111 
2112  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2113  {
2114  if(InactiveTrackElementAt(119, IMPair.first).TrackType == NamedNonStationLocation)
2115  NonStationOrLevelCrossingPresent = true;
2116  if(InactiveTrackElementAt(120, IMPair.first).TrackType == LevelCrossing)
2117  NonStationOrLevelCrossingPresent = true;
2118  if(InactiveTrackElementAt(121, IMPair.first).TrackType == Platform)
2119  PlatformPresent = true;
2120  // no need to check IMPair.second since if that exists it is because .first is a platform
2121  InactiveSpeedTag1 = InactiveTrackElementAt(122, IMPair.first).SpeedTag;
2122  InactiveSpeedTag2 = InactiveTrackElementAt(123, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2123  }
2124 
2125 // check platforms
2126  if(TempTrackElement.TrackType == Platform)
2127  {
2128  if(FoundFlag) // active track element already there
2129  {
2130  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2131  {;
2132  }
2133  // same platform type already there so above keeps PlatAllowedFlag false
2134  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2135  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2136  {
2137  PlatAllowedFlag = true;
2138  }
2139  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2140  {
2141  PlatAllowedFlag = true;
2142  }
2143  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2144  {
2145  PlatAllowedFlag = true;
2146  }
2147  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2148  {
2149  PlatAllowedFlag = true;
2150  }
2151  if(PlatAllowedFlag)
2152  {
2153  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2154  TrackPush(12, TempTrackElement);
2155 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2156  {
2157  SearchForAndUpdateLocationName(4, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2158  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2159  }
2160  // Must be called AFTER TrackPush
2161 // No need to plot the element - Clearand ... called after this function called
2162  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2163  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2164 // drop in v2.4.0 if(TrackElementAt(907, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2165 // AnsiString(TrackElementAt(908, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2166 // TrackElementAt(909, VecPos).Length01 = DefaultTrackLength;
2167  if(InternalChecks)
2168  {
2169  CheckMapAndInactiveTrack(12); // test
2170  CheckLocationNameMultiMap(20); // test
2171  }
2172  Utilities->CallLogPop(2064);
2173  return;
2174  }
2175  } // if(FoundFlag)
2176  Utilities->CallLogPop(2065);
2177  return;
2178  } // if platform
2179 
2180 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2181  if(TempTrackElement.TrackType == NamedNonStationLocation)
2182  {
2183  if((FoundFlag && (NameAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2184  (!FoundFlag && !InactiveFoundFlag))
2185  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2186  {
2187  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2188  TrackPush(13, TempTrackElement);
2189 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2190  {
2191  SearchForAndUpdateLocationName(5, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2192  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2193  }
2194  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2195  {
2196 // drop in v2.4.0 if(TrackElementAt(910, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2197 // AnsiString(TrackElementAt(911, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2198 // TrackElementAt(912, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2199  }
2200  if(InternalChecks)
2201  {
2202  CheckMapAndInactiveTrack(13); // test
2203  CheckLocationNameMultiMap(21); // test
2204  }
2205  Utilities->CallLogPop(2066);
2206  return;
2207  }
2208  else
2209  {
2210  Utilities->CallLogPop(2067);
2211  return;
2212  }
2213  }
2214 
2215 // check if a level crossing - OK if placed on a plain straight track
2216  if(TempTrackElement.TrackType == LevelCrossing)
2217  {
2218  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2219  {
2220  TrackPush(14, TempTrackElement);
2221  PlotRaisedLinkedLevelCrossingBarriers(3, TrackVector.at(VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2222 // no need for reference to LC element as can't be open
2223  TrackLinkingRequiredFlag = true;
2224  Utilities->CallLogPop(2068);
2225  return;
2226  }
2227  else
2228  {
2229  Utilities->CallLogPop(2069);
2230  return; // was a level crossing but can't place it for some reason
2231  }
2232  }
2233 
2234 // check if another element already there
2235  else if(FoundFlag || InactiveFoundFlag)
2236  {
2237  Utilities->CallLogPop(2070);
2238  return; // something already there (active or inactive track)
2239  }
2240 
2241 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2242 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2243 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2244 // do this after pushed into vector so that can use EnterLocationName
2245 
2246  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2247  {
2248  TrackPush(15, TempTrackElement);
2249  SearchForAndUpdateLocationName(6, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2250  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2251  }
2252  else if(TempTrackElement.TrackType == Points)
2253  {
2254  TrackPush(16, TempTrackElement);
2255  bool BothPointFillets = true;
2256  PlotPoints(7, TempTrackElement, Display, BothPointFillets);
2257  }
2258  else if(TempTrackElement.TrackType == SignalPost)
2259  {
2260  TrackPush(17, TempTrackElement);
2261  PlotSignal(14, TempTrackElement, Display);
2262  }
2263  else
2264  {
2265  TrackPush(18, TempTrackElement);
2266  TempTrackElement.PlotVariableTrackElement(6, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2267  }
2268  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2269  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2270  if(InternalChecks)
2271  {
2272  CheckMapAndTrack(12); // test
2273  CheckMapAndInactiveTrack(14); // test
2274  CheckLocationNameMultiMap(22); // test
2275  }
2276  Utilities->CallLogPop(2071);
2277 }
2278 
2279 // ---------------------------------------------------------------------------
2280 
2281 bool TTrack::TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
2282  // GiveMessages relates to the call to LinkTrack or LinkTrackNoMessages
2283  // return bool = true for success
2284  // LocError = true for location error & HLoc & VLoc to be inverted
2285 {
2286  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TryToConnectTrack," + AnsiString((short)GiveMessages));
2287  LocError = false;
2288  SetTrackFinished(false);
2289  if(TrackVector.size() == 0)
2290  {
2291  Utilities->CallLogPop(437);
2292  return false;
2293  }
2294  if(GapsUnset(7))
2295  {
2296  if(GiveMessages)
2297  ShowMessage("Gaps must be set before track can be validated");
2298  Utilities->CallLogPop(1135);
2299  return false;
2300  }
2301 // below sets all Conns and CLks to -1 except for gapjumps that match and are properly set,
2302 // returns true for any unset gaps
2304  {
2305  // can keep this exception as protected by the GapsUnset call above
2306  throw Exception("Error, gaps unset when TryToConnectTrack called");
2307  }
2309  CheckGapMap(1); // test
2310 // Gap connections now securely defined
2311 
2312  CheckMapAndTrack(8); // test
2313 
2314 // Perform a pre-check prior to TrackMap being compiled
2315  if(GiveMessages)
2316  {
2317  if(!LinkTrack(1, LocError, HLoc, VLoc, false))
2318  {
2319  Utilities->CallLogPop(439);
2320  return false;
2321  }
2322  }
2323  else
2324  {
2325  if(!LinkTrackNoMessages(1, false))
2326  {
2327  Utilities->CallLogPop(1131);
2328  return false;
2329  }
2330  }
2331 
2332 // here if pre-check successful
2333  if(!RepositionAndMapTrack(0))
2334  {
2335  ShowMessage("Error in RepositionAndMapTrack during TryToConnectTrack. Railway file is corrupt, further use may cause a system crash");
2336  Utilities->CallLogPop(1138);
2337  return false;
2338  }
2339 // now perform the final assembly - FinalCall = true
2340  if(GiveMessages)
2341  {
2342  if(!LinkTrack(2, LocError, HLoc, VLoc, true))
2343  {
2344  Utilities->CallLogPop(1116);
2345  return false;
2346  }
2347  }
2348  else
2349  {
2350  if(!LinkTrackNoMessages(2, true))
2351  {
2352  Utilities->CallLogPop(1132);
2353  return false;
2354  }
2355  }
2356 
2357 // success
2358 
2359  PopulateLCVector(0);
2360  CheckGapMap(2); // test
2361  CheckMapAndTrack(3); // test
2362  CheckMapAndInactiveTrack(3); // test
2363  CheckLocationNameMultiMap(9); // test
2364  SetTrackFinished(true);
2365 
2366 // Build ContinuationNameMap
2367  std::pair<AnsiString, char>TempMapPair;
2368 
2369  ContinuationNameMap.clear();
2370  for(int x = 0; x < Track->TrackVectorSize(); x++)
2371  {
2372  if((Track->TrackVector.at(x).TrackType == Continuation) && (Track->TrackVector.at(x).ActiveTrackElementName != ""))
2373  {
2374  TempMapPair.first = Track->TrackVector.at(x).ActiveTrackElementName;
2375  TempMapPair.second = 'x'; // unused
2376  ContinuationNameMap.insert(TempMapPair);
2377  }
2378  }
2379  Utilities->CallLogPop(440);
2380  return true;
2381 }
2382 
2383 // ---------------------------------------------------------------------------
2384 bool TTrack::ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
2385  // unused - too time-consuming - double brute force search
2386 {
2387  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErrorInTrackBeforeSetGaps");
2388  int NewHLoc, NewVLoc;
2389  bool ConnectionFoundFlag, LinkFoundFlag;
2390 
2391  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
2392  {
2393  for(unsigned int y = 0; y < 4; y++) // check all links for each element
2394  {
2395  if(TrackVector.at(x).Link[y] <= 0)
2396  continue; // no link
2397  if(TrackVector.at(x).Config[y] == End)
2398  continue; // buffer or continuation
2399  if(TrackVector.at(x).Config[y] == Gap)
2400  continue; // gap jump
2401  // get required H & V for track element joining link 'y'
2402  NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
2403  NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
2404  // find track element if present
2405  ConnectionFoundFlag = false;
2406  for(unsigned int z = 0; z < TrackVector.size(); z++)
2407  {
2408 // if(TrackElementAt(5, z).TrackType == Platform)
2409 // continue; //skip platforms
2410  if((TrackVector.at(z).HLoc == NewHLoc) && (TrackVector.at(z).VLoc == NewVLoc))
2411  {
2412  ConnectionFoundFlag = true;
2413  // find connecting link in the newly found track element if there is one
2414  LinkFoundFlag = false;
2415  for(unsigned int a = 0; a < 4; a++)
2416  {
2417  if(TrackVector.at(z).Link[a] == (10 - TrackVector.at(x).Link[y]))
2418  {
2419  LinkFoundFlag = true;
2420  }
2421  }
2422  // if there isn't a corresponding link set the invert values for the offending element
2423  if(!LinkFoundFlag)
2424  {
2425  HLoc = TrackVector.at(x).HLoc;
2426  VLoc = TrackVector.at(x).VLoc;
2427  Utilities->CallLogPop(441);
2428  return true;
2429  }
2430  break; // success, so break out of 'z' loop
2431  } // if((TrackVector.at(z).HLoc== NewHLoc) &&....
2432  } // for z...
2433  // if there isn't a connection set the invert values for the offending element
2434  if(!ConnectionFoundFlag)
2435  {
2436  HLoc = TrackVector.at(x).HLoc;
2437  VLoc = TrackVector.at(x).VLoc;
2438  Utilities->CallLogPop(442);
2439  return true;
2440  }
2441  } // for y....
2442  } // for x...
2443  Utilities->CallLogPop(443);
2444  return false; // all OK
2445 }
2446 
2447 // ---------------------------------------------------------------------------
2448 
2449 bool TTrack::FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement) // true if find one
2450 {
2451  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNonPlatformMatch," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
2452  TrackElement.LogTrack(0));
2453  bool FoundFlag;
2454 
2455  Position = GetVectorPositionFromTrackMap(13, HLoc, VLoc, FoundFlag);
2456  if(FoundFlag)
2457  TrackElement = TrackVector.at(Position);
2458  Utilities->CallLogPop(444);
2459  return FoundFlag;
2460 }
2461 
2462 // ---------------------------------------------------------------------------
2463 
2465 {
2466  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextTrackElement");
2467  if(NextTrackElementPtr >= TrackVector.end())
2468  {
2469  Utilities->CallLogPop(1336);
2470  return false;
2471  }
2472  Next = *NextTrackElementPtr;
2474  Utilities->CallLogPop(1337);
2475  return true;
2476 }
2477 
2478 // ---------------------------------------------------------------------------
2479 
2481 {
2482  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextInactiveTrackElement");
2484  {
2485  Utilities->CallLogPop(1338);
2486  return false;
2487  }
2488  Next = *NextTrackElementPtr;
2490  Utilities->CallLogPop(1339);
2491  return true;
2492 }
2493 
2494 // ---------------------------------------------------------------------------
2495 
2496 int TTrack::NumberOfGaps(int Caller)
2497 
2498 {
2499  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfGaps");
2500  int Count = 0;
2501 
2502  if(TrackVector.size() == 0)
2503  {
2504  Utilities->CallLogPop(1340);
2505  return 0;
2506  }
2507  for(unsigned int x = 0; x < TrackVector.size(); x++)
2508  {
2509  if(TrackVector.at(x).TrackType == GapJump)
2510  Count++;
2511  }
2512  Utilities->CallLogPop(1341);
2513  return Count;
2514 }
2515 
2516 // ---------------------------------------------------------------------------
2518  // above sets all Conns and CLks to -1 except for gapjumps that match and are properly set
2519  // returns true for any unset gaps
2520 {
2521  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetConnClkCheckUnsetGapJumps");
2522  bool UnsetGaps = false;
2523 
2524  if(TrackVector.size() == 0)
2525  {
2526  Utilities->CallLogPop(445);
2527  return false;
2528  }
2529  for(unsigned int x = 0; x < TrackVector.size(); x++)
2530  {
2531  if(TrackVector.at(x).TrackType != GapJump)
2532  {
2533  for(unsigned int y = 0; y < 4; y++)
2534  {
2535  TrackVector.at(x).Conn[y] = -1;
2536  TrackVector.at(x).ConnLinkPos[y] = -1;
2537  }
2538  }
2539  else // GapJump
2540  {
2541 // int tempint = TrackVector.at(x).Conn[0);
2542 
2543  if(TrackVector.at(x).Conn[0] == -1) // unset if -1
2544  {
2545  for(unsigned int y = 0; y < 4; y++)
2546  {
2547  TrackVector.at(x).Conn[y] = -1;
2548  TrackVector.at(x).ConnLinkPos[y] = -1;
2549  }
2550  UnsetGaps = true;
2551  continue; // to next 'x'
2552  }
2553  else // set, but may not have matching element, or that element may not be set
2554  {
2555  for(unsigned int y = 1; y < 4; y++) // reset the non-gap values anyway, gap always at position 0
2556  {
2557  TrackVector.at(x).Conn[y] = -1;
2558  TrackVector.at(x).ConnLinkPos[y] = -1;
2559  }
2560 
2561  if(TrackVector.at(TrackVector.at(x).Conn[0]).TrackType != GapJump)
2562  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks & reset Lk[0]
2563  {
2564  for(unsigned int y = 0; y < 4; y++)
2565  {
2566  TrackVector.at(x).Conn[y] = -1;
2567  TrackVector.at(x).ConnLinkPos[y] = -1;
2568  }
2569  UnsetGaps = true;
2570  continue; // to next 'x'
2571  }
2572 // here if gap connection is itself a GapJump
2573  if(TrackVector.at(TrackVector.at(x).Conn[0]).Conn[0] != (int)x)
2574  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
2575  // if not clear Conns & CLks & reset Lk[0]
2576  {
2577  for(unsigned int y = 0; y < 4; y++)
2578  {
2579  TrackVector.at(x).Conn[y] = -1;
2580  TrackVector.at(x).ConnLinkPos[y] = -1;
2581  }
2582  UnsetGaps = true;
2583  continue; // to next 'x'
2584  }
2585 // here if gap connection itself points back to 'x' so these two GapJumps match properly
2586 // hence no more action needed on these Conns & CLks
2587  }
2588  } // else //gap jump
2589  } // for x...
2590  Utilities->CallLogPop(446);
2591  return UnsetGaps;
2592 }
2593 
2594 // ---------------------------------------------------------------------------
2595 
2596 void TTrack::LoadTrack(int Caller, std::ifstream& VecFile, bool &GraphicsFollow)
2597 {
2598 // VecFile already open and its pointer at right place on calling
2599  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTrack");
2600  int TempInt;
2601 
2602  TrackClear(1);
2603 // load track elements
2604  int NumberOfActiveElements = 0;
2605 
2606  GraphicsFollow = false;
2607  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
2608  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // **Active elements** marker, if last character is '1' then there are graphics to be loaded
2609 
2610  if(MarkerString[MarkerString.Length()] == '1')
2611  {
2612  GraphicsFollow = true;
2613  }
2614  for(int x = 0; x < NumberOfActiveElements; x++)
2615  {
2616  VecFile >> TempInt; // TrackVectorNumber, not used
2617  VecFile >> TempInt; // SpeedTag
2618  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
2619  VecFile >> TempInt;
2620  TrackElement.HLoc = TempInt;
2621  VecFile >> TempInt;
2622  TrackElement.VLoc = TempInt;
2623  if(TrackElement.TrackType == GapJump)
2624  {
2625  VecFile >> TempInt;
2626  TrackElement.ConnLinkPos[0] = TempInt;
2627  VecFile >> TempInt;
2628  TrackElement.Conn[0] = TempInt;
2629  }
2630  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
2631  {
2632  VecFile >> TempInt;
2633  TrackElement.Attribute = TempInt;
2634  }
2635  if(TrackElement.TrackType == SignalPost)
2636  {
2637  VecFile >> TempInt;
2638  if(TempInt == 0)
2639  TrackElement.CallingOnSet = false;
2640  else
2641  TrackElement.CallingOnSet = true;
2642  }
2643  VecFile >> TempInt;
2644  TrackElement.Length01 = TempInt;
2645  VecFile >> TempInt;
2646  TrackElement.Length23 = TempInt;
2647  VecFile >> TempInt;
2648  if((TempInt != -1) && (TempInt < 10))
2649  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
2650  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
2651  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
2652  TrackElement.SpeedLimit01 = TempInt;
2653  VecFile >> TempInt;
2654  if((TempInt != -1) && (TempInt < 10))
2655  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
2656  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
2657  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
2658  TrackElement.SpeedLimit23 = TempInt;
2659 
2660  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
2661  TrackElement.ActiveTrackElementName = Utilities->LoadFileString(VecFile);
2662  SetElementID(0, TrackElement);
2663  AnsiString Marker = Utilities->LoadFileString(VecFile); // marker
2664 // new for v0.6
2665  if(TrackElement.TrackType == SignalPost)
2666  {
2667  if(Marker[1] == '3')
2668  {
2669  TrackElement.SigAspect = TTrackElement::ThreeAspect;
2670  }
2671  else if(Marker[1] == '2')
2672  {
2673  TrackElement.SigAspect = TTrackElement::TwoAspect;
2674  }
2675  else if(Marker[1] == 'G')
2676  {
2677  TrackElement.SigAspect = TTrackElement::GroundSignal;
2678  }
2679  else
2680  {
2681  TrackElement.SigAspect = TTrackElement::FourAspect;
2682  }
2683  }
2684  if(TrackElement.SpeedTag != 0)
2685  TrackPush(8, TrackElement); // don't save default elements (now dispensed with)
2686  }
2687  int NumberOfInactiveElements = 0;
2688 
2689  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
2690  Utilities->LoadFileString(VecFile); // **Inactive elements** marker
2691  for(int x = 0; x < NumberOfInactiveElements; x++)
2692  {
2693  VecFile >> TempInt; // InactiveTrackVectorNumber - not used, only used for identification in file
2694  VecFile >> TempInt; // SpeedTag
2695  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
2696  VecFile >> TempInt;
2697  TrackElement.HLoc = TempInt;
2698  VecFile >> TempInt;
2699  TrackElement.VLoc = TempInt;
2700  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
2701  SetElementID(3, TrackElement);
2702  TrackPush(9, TrackElement);
2703  Utilities->LoadFileString(VecFile); // marker
2704  }
2705  bool LocError = false; // needed for TryToConnectTrack but not used
2706  int H = -1, V = -1; // needed for TryToConnectTrack but not used
2707 
2708  if(TryToConnectTrack(2, LocError, H, V, false)) // false for don't give messages
2709  {
2710  SetTrackFinished(true);
2711  }
2712  else
2713  {
2714  SetTrackFinished(false);
2715  }
2716 // CheckMapAndTrack(9); all these checked in TryToConnectTrack
2717 // CheckMapAndInactiveTrack(8);
2718 // CheckLocationNameMultiMap(10);
2719  Utilities->CallLogPop(448);
2720 }
2721 
2722 // ---------------------------------------------------------------------------
2723 
2724 void TTrack::LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
2725 {
2726 // VecFile already open and its pointer at right place on calling
2727  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGraphics, " + GraphicsPath);
2728 // first int is number of graphics, then each graphic, create in UserGraphicMap, derive Width & height from TPicture
2729 // & load into UserGraphicItem then store in UserGraphicVector
2730  UserGraphicVector.clear();
2731  TUserGraphicItem UGI;
2732  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
2733 
2734  for(int x = 0; x < NumberOfGraphics; x++)
2735  {
2736  UGI.FileName = GraphicsPath + "\\" + Utilities->LoadFileString(VecFile);
2737  UGI.HPos = Utilities->LoadFileInt(VecFile);
2738  UGI.VPos = Utilities->LoadFileInt(VecFile);
2739  UGI.Width = 0; // provisional value
2740  UGI.Height = 0; // provisional value
2741  UGI.UserGraphic = NULL; // provisional value
2742  UserGraphicVector.push_back(UGI);
2743  }
2744 // now load the map & set Width, Height & TPicture*
2745  bool FileError = false;
2746 
2747  for(int x = 0; x < NumberOfGraphics; x++)
2748  {
2749  if(FileError)
2750  {
2751  break; // otherwise keeps going round the loop
2752  }
2753  UGI = UserGraphicVectorAt(0, x);
2754  if(UserGraphicMap.empty()) // will be when x == 0 but not after
2755  {
2756  try
2757  {
2758 // TUserGraphicMapEntry UGME; //can't define it here, it has to be defined before it is used - now defined in TrackUnit.h
2759  UGME.first = UGI.FileName;
2760  UGME.second = new TPicture;
2761  UGME.second->LoadFromFile(UGME.first); // errors caught below
2762  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
2763  {
2764  throw Exception("Map Insertion Error 2 - UserGraphicMap insertion failure for " + UGI.FileName);
2765  }
2766  UGI.UserGraphic = UGME.second;
2767  UGI.Width = UGI.UserGraphic->Width;
2768  UGI.Height = UGI.UserGraphic->Height;
2769  UserGraphicVectorAt(1, x) = UGI;
2770  }
2771  catch(const EInvalidGraphic &e)
2772  {
2773  //message already sent in CheckUserGraphics
2774  FileError = true;
2775  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
2776  if(!UserGraphicMap.empty())
2777  {
2778  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
2779  {
2780  delete UGMIt->second;
2781  }
2782  UserGraphicMap.clear();
2783  }
2784  }
2785  catch(const Exception &e)
2786  {
2787  //message already sent in CheckUserGraphics
2788  FileError = true;
2789  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
2790  if(!UserGraphicMap.empty())
2791  {
2792  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
2793  {
2794  delete UGMIt->second;
2795  }
2796  UserGraphicMap.clear();
2797  }
2798  }
2799  }
2800  else
2801  {
2802  bool FoundInMap = false;
2803  for(TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
2804  {
2805  if(UGI.FileName == UGMIt->first) // already exists in map
2806  {
2807  UGI.UserGraphic = UGMIt->second;
2808  UGI.Width = UGI.UserGraphic->Width;
2809  UGI.Height = UGI.UserGraphic->Height;
2810  UserGraphicVectorAt(2, x) = UGI;
2811  FoundInMap = true;
2812  break;
2813  }
2814  }
2815  if(!FoundInMap)
2816  {
2817  try
2818  {
2820  UGME.first = UGI.FileName;
2821  UGME.second = new TPicture;
2822  UGME.second->LoadFromFile(UGME.first); // errors caught below
2823  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
2824  {
2825  throw Exception("Map Insertion Error 3 - UserGraphicMap insertion failure for " + UGI.FileName);
2826  }
2827  UGI.UserGraphic = UGME.second;
2828  UGI.Width = UGI.UserGraphic->Width;
2829  UGI.Height = UGI.UserGraphic->Height;
2830  UserGraphicVectorAt(3, x) = UGI;
2831  }
2832  catch(const EInvalidGraphic &e)
2833  {
2834  //message already sent in CheckUserGraphics
2835  FileError = true;
2836  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
2837  if(!UserGraphicMap.empty())
2838  {
2839  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
2840  {
2841  delete UGMIt->second;
2842  }
2843  UserGraphicMap.clear();
2844  }
2845  }
2846  catch(const Exception &e)
2847  {
2848  //message already sent in CheckUserGraphics
2849  FileError = true;
2850  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
2851  if(!UserGraphicMap.empty())
2852  {
2853  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
2854  {
2855  delete UGMIt->second;
2856  }
2857  UserGraphicMap.clear();
2858  }
2859  }
2860  }
2861  }
2862  }
2863  Utilities->CallLogPop(2167);
2864 }
2865 
2866 // ---------------------------------------------------------------------------
2867 
2868 void TTrack::SaveTrack(int Caller, std::ofstream& VecFile, bool GraphicsFollow)
2869 {
2870 // VecFile already open and its pointer at right place on calling
2871 // if GraphicsFollow true, then save Marker as **Active elements**1
2872 // save trackfinished flag
2873  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTrack, " + AnsiString(int(GraphicsFollow)));
2874  TTrackElement TrackElement, InactiveTrackElement;
2875 
2876 // save track elements
2877  Utilities->SaveFileInt(VecFile, TrackVector.size());
2878  if(GraphicsFollow)
2879  {
2880  VecFile << "**Active elements**1" << '\0' << '\n';
2881  }
2882  else
2883  {
2884  VecFile << "**Active elements**" << '\0' << '\n';
2885  }
2886  for(unsigned int x = 0; x < (TrackVector.size()); x++)
2887  {
2888  TrackElement = TrackVector.at(x);
2889  VecFile << x << '\n'; // this is the TrackVectorNumber - extra, so easier to identify in the file
2890  VecFile << TrackElement.SpeedTag << '\n';
2891  VecFile << TrackElement.HLoc << '\n';
2892  VecFile << TrackElement.VLoc << '\n';
2893  if(TrackElement.TrackType == GapJump)
2894  {
2895  VecFile << TrackElement.ConnLinkPos[0] << '\n';
2896  VecFile << TrackElement.Conn[0] << '\n';
2897  }
2898  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
2899  {
2900  VecFile << TrackElement.Attribute << '\n';
2901  }
2902  if(TrackElement.TrackType == SignalPost)
2903  {
2904  if(TrackElement.CallingOnSet)
2905  VecFile << int(1) << '\n';
2906  else
2907  VecFile << int(0) << '\n';
2908  }
2909  VecFile << TrackElement.Length01 << '\n';
2910  VecFile << TrackElement.Length23 << '\n';
2911  VecFile << TrackElement.SpeedLimit01 << '\n';
2912  VecFile << TrackElement.SpeedLimit23 << '\n';
2913  VecFile << TrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2914  VecFile << TrackElement.ActiveTrackElementName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2915 // new for v0.6
2916  if(TrackElement.TrackType == SignalPost)
2917  {
2918  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
2919  {
2920  VecFile << "3*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2921  }
2922  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
2923  {
2924  VecFile << "2*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2925  }
2926  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
2927  {
2928  VecFile << "G*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2929  }
2930  else // 4 aspect
2931  {
2932  VecFile << "4*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2933  }
2934  }
2935  else
2936  {
2937  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2938  }
2939  }
2940 
2941  Utilities->SaveFileInt(VecFile, InactiveTrackVector.size());
2942  VecFile << "**Inactive elements**" << '\0' << '\n'; // extra
2943  for(unsigned int x = 0; x < (InactiveTrackVector.size()); x++)
2944  {
2945  InactiveTrackElement = InactiveTrackVector.at(x);
2946  VecFile << x << '\n'; // this is the Inactive TrackVectorNumber - extra
2947  VecFile << InactiveTrackElement.SpeedTag << '\n';
2948  VecFile << InactiveTrackElement.HLoc << '\n';
2949  VecFile << InactiveTrackElement.VLoc << '\n';
2950  VecFile << InactiveTrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2951  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2952  }
2953  Utilities->CallLogPop(449);
2954 }
2955 
2956 // ---------------------------------------------------------------------------
2957 
2958 bool TTrack::CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream& VecFile)
2959 {
2960 // VecFile already open and its pointer at right place on calling
2961 // check trackfinished flag
2962 // inactive elements follow immediately after active elements, no need to check for a marker between them
2963  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTrackElementsInFile");
2964  int TempInt;
2965 
2966  GraphicsFollow = false;
2967  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
2968  if((NumberOfActiveElements < 0) || (NumberOfActiveElements > 1000000)) // No of active elements (up to 500 screens all completely full!)
2969  {
2970  Utilities->CallLogPop(1513);
2971  return false;
2972  }
2973 // if(!Utilities->CheckAndCompareFileString(VecFile, "**Active elements**")) dropped at v2.4.0 as could have a '1' at the end if there are graphics
2974  AnsiString MarkerString;
2975 
2976  if(!Utilities->CheckAndReadFileString(VecFile, MarkerString)) // new version for v2.4.0
2977  {
2978  Utilities->CallLogPop(1758);
2979  return false;
2980  }
2981  if(MarkerString[MarkerString.Length()] == '1')
2982  {
2983  GraphicsFollow = true;
2984  }
2985  for(int x = 0; x < NumberOfActiveElements; x++)
2986  {
2987  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
2988  {
2989  Utilities->CallLogPop(1759);
2990  return false;
2991  }
2992  VecFile >> TempInt;
2993  int SpeedTag = TempInt;
2994  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
2995  {
2996  Utilities->CallLogPop(1514);
2997  return false;
2998  }
2999  VecFile >> TempInt;
3000  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3001  {
3002  Utilities->CallLogPop(1495);
3003  return false;
3004  }
3005  VecFile >> TempInt;
3006  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3007  {
3008  Utilities->CallLogPop(1497);
3009  return false;
3010  }
3011  if((SpeedTag > 87) && (SpeedTag < 96)) // GapJumps 88-95 incl
3012  {
3013  VecFile >> TempInt;
3014  if((TempInt < -1) || (TempInt > 3)) // ConnLinkPos[0]
3015  {
3016  Utilities->CallLogPop(1499);
3017  return false;
3018  }
3019  VecFile >> TempInt;
3020  if((TempInt < -1) || (TempInt > 999999)) // Conn[0]
3021  {
3022  Utilities->CallLogPop(1500);
3023  return false;
3024  }
3025  }
3026  if(((SpeedTag >= 7) && (SpeedTag <= 14)) || ((SpeedTag >= 28) && (SpeedTag <= 43)) || ((SpeedTag >= 132) && (SpeedTag <= 139)) ||
3027  ((SpeedTag >= 68) && (SpeedTag <= 75)))
3028  {
3029  VecFile >> TempInt;
3030  if((TempInt < -1) || (TempInt > 5)) // Points & signal attribute
3031  {
3032  Utilities->CallLogPop(1502);
3033  return false;
3034  }
3035  }
3036  if((SpeedTag >= 68) && (SpeedTag <= 75)) // signals
3037  {
3038  VecFile >> TempInt;
3039  if((TempInt != 0) && (TempInt != 1)) // CallingOnSet
3040  {
3041  Utilities->CallLogPop(1155);
3042  return false;
3043  }
3044  }
3045  VecFile >> TempInt;
3046  if((TempInt < -1) || (TempInt > 999999)) // Length01
3047  {
3048  Utilities->CallLogPop(1503);
3049  return false;
3050  }
3051  VecFile >> TempInt;
3052  if((TempInt < -1) || (TempInt > 999999)) // Length23
3053  {
3054  Utilities->CallLogPop(1504);
3055  return false;
3056  }
3057  VecFile >> TempInt;
3058  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit01
3059  {
3060  Utilities->CallLogPop(1505);
3061  return false;
3062  }
3063  VecFile >> TempInt;
3064  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit23
3065  {
3066  Utilities->CallLogPop(1506);
3067  return false;
3068  }
3069  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3070  {
3071  Utilities->CallLogPop(1142);
3072  return false; // LocationName
3073  }
3074  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3075  {
3076  Utilities->CallLogPop(1143);
3077  return false; // ActiveTrackElementName
3078  }
3079  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3080  {
3081  Utilities->CallLogPop(1787);
3082  return false; // marker
3083  }
3084  }
3085  int NumberOfInactiveElements = 0;
3086 
3087  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3088  if(NumberOfInactiveElements < 0) // No of active elements
3089  {
3090  Utilities->CallLogPop(1493);
3091  return false;
3092  }
3093  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3094  {
3095  Utilities->CallLogPop(1764);
3096  return false; // **Inactive elements** marker
3097  }
3098  for(int x = 0; x < NumberOfInactiveElements; x++)
3099  {
3100  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3101  {
3102  Utilities->CallLogPop(1765);
3103  return false;
3104  }
3105  VecFile >> TempInt;
3106  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3107  {
3108  Utilities->CallLogPop(1494);
3109  return false;
3110  }
3111  VecFile >> TempInt;
3112  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3113  {
3114  Utilities->CallLogPop(1496);
3115  return false;
3116  }
3117  VecFile >> TempInt;
3118  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3119  {
3120  Utilities->CallLogPop(1498);
3121  return false;
3122  }
3123  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3124  {
3125  Utilities->CallLogPop(1144);
3126  return false; // LocationName
3127  }
3128  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3129  {
3130  Utilities->CallLogPop(1788);
3131  return false; // marker
3132  }
3133  }
3134  Utilities->CallLogPop(1507);
3135  return true;
3136 }
3137 
3138 // ---------------------------------------------------------------------------
3139 
3140 bool TTrack::CheckUserGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3141 {
3142  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckUserGraphics");
3143  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3144 
3145  if((NumberOfGraphics < 0) || (NumberOfGraphics > 100000)) // 100,000 should be plenty!
3146  {
3147  Utilities->CallLogPop(2168);
3148  return false;
3149  }
3150  // filename in Graphics folder, then HPos, then VPos
3151  AnsiString FileName = "", TempStr = "";
3152 
3153  for(int x = 0; x < NumberOfGraphics; x++)
3154  {
3155  TPicture *TempPicture = new TPicture;
3156  try
3157  {
3158  if(!Utilities->CheckAndReadFileString(VecFile, FileName))
3159  {
3160  Utilities->CallLogPop(2169);
3161  delete TempPicture;
3162  return false;
3163  }
3164  TempPicture->LoadFromFile(GraphicsPath + "\\" + FileName); // only loaded to check and catch errors
3165  delete TempPicture;
3166  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // HPos, allow plenty of scope
3167  {
3168  Utilities->CallLogPop(2170);
3169  return false;
3170  }
3171  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // VPos
3172  {
3173  Utilities->CallLogPop(2171);
3174  return false;
3175  }
3176  }
3177  catch(const EInvalidGraphic &e)
3178  {
3179  //move file pointer to end of graphic section for later checks in session files
3180  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3181  Utilities->CheckAndReadFileString(VecFile, TempStr);//VPos
3182  for(int y = x + 1; y < NumberOfGraphics; y++)
3183  {
3184  Utilities->CheckAndReadFileString(VecFile, TempStr);//next FileName
3185  Utilities->CheckAndReadFileString(VecFile, TempStr);//next VPos
3186  Utilities->CheckAndReadFileString(VecFile, TempStr);//next VPos
3187  }
3188  ShowMessage(FileName +
3189  " has an incorrect file format, user graphics can't be loaded. Ensure that all user graphic files are valid with extension .bmp, .gif, .jpg, or .png");
3190  Utilities->CallLogPop(2172);
3191  delete TempPicture;
3192  return true; //for these file errors allow railway or session to be loaded, changed at v2.6.0
3193  }
3194  catch(const Exception &e)
3195  {
3196  //move file pointer to end of graphic section for later checks in session files
3197  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3198  Utilities->CheckAndReadFileString(VecFile, TempStr);//VPos
3199  for(int y = x + 1; y < NumberOfGraphics; y++)
3200  {
3201  Utilities->CheckAndReadFileString(VecFile, TempStr);//next FileName
3202  Utilities->CheckAndReadFileString(VecFile, TempStr);//next VPos
3203  Utilities->CheckAndReadFileString(VecFile, TempStr);//next VPos
3204  }
3205  ShowMessage("Unable to load user graphic files, ensure that " + FileName +
3206  " exists in the 'Graphics' folder and that it is has extension .bmp, .gif, .jpg, or .png.");
3207  Utilities->CallLogPop(2173);
3208  delete TempPicture;
3209  return true; //for these file errors allow railway or session to be loaded, changed at v2.6.0
3210  }
3211  }
3212  Utilities->CallLogPop(2174);
3213  return true;
3214 }
3215 
3216 // ---------------------------------------------------------------------------
3217 
3218 void TTrack::SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
3219 {
3220  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSessionBarriersDownVector");
3221  int VecSize = Track->BarriersDownVector.size();
3222 
3223  Utilities->SaveFileInt(OutFile, VecSize);
3224  for(int x = 0; x < VecSize; x++)
3225  {
3227  Utilities->SaveFileInt(OutFile, TALC.ConsecSignals); //changed to int from bool in v2.6.0
3228  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3229  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3230  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3231  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3232  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3233  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3234  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3235  }
3236  Utilities->CallLogPop(1963);
3237 }
3238 
3239 // ---------------------------------------------------------------------------
3240 
3241 void TTrack::SaveChangingLCVector(int Caller, std::ofstream &OutFile) //used only in errorfile
3242 {
3243  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveChangingLCVector");
3244  int VecSize = Track->ChangingLCVector.size();
3245 
3246  Utilities->SaveFileInt(OutFile, VecSize);
3247  for(int x = 0; x < VecSize; x++)
3248  {
3250  Utilities->SaveFileInt(OutFile, TALC.ConsecSignals); //changed to int from bool in v2.6.0
3251  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3252  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3253  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3254  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3255  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3256  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3257  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3258  }
3259  Utilities->CallLogPop(1980);
3260 }
3261 
3262 // ---------------------------------------------------------------------------
3263 
3264 bool TTrack::CheckActiveLCVector(int Caller, std::ifstream &VecFile)
3265 {
3266  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckActiveLCVector");
3267  int VecSize = Utilities->LoadFileInt(VecFile);
3268 
3269  for(int x = 0; x < VecSize; x++)
3270  {
3271  if(!Utilities->CheckFileInt(VecFile, 0, 2)) //changed from bool at v2.6.0 to allow ConsecSignals == 2 for barriers manually lowered
3272  {
3273  Utilities->CallLogPop(1970);
3274  return false;
3275  }
3276  if(!Utilities->CheckFileBool(VecFile))
3277  {
3278  Utilities->CallLogPop(1971);
3279  return false;
3280  }
3281  if(!Utilities->CheckFileInt(VecFile, 0, 3))
3282  {
3283  Utilities->CallLogPop(1972);
3284  return false;
3285  }
3286  if(!Utilities->CheckFileDouble(VecFile))
3287  {
3288  Utilities->CallLogPop(1973);
3289  return false;
3290  }
3291  if(!Utilities->CheckFileInt(VecFile, 1, 2))
3292  {
3293  Utilities->CallLogPop(1974);
3294  return false;
3295  }
3296  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3297  {
3298  Utilities->CallLogPop(1975);
3299  return false;
3300  }
3301  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3302  {
3303  Utilities->CallLogPop(1976);
3304  return false;
3305  }
3306  if(!Utilities->CheckFileDouble(VecFile))
3307  {
3308  Utilities->CallLogPop(1977);
3309  return false;
3310  }
3311  }
3312  Utilities->CallLogPop(1978);
3313  return true;
3314 }
3315 
3316 // ---------------------------------------------------------------------------
3317 
3318 void TTrack::LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
3319 {
3320  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadBarriersDownVector");
3321  int VecSize = Utilities->LoadFileInt(VecFile);
3322 
3323  for(int x = 0; x < VecSize; x++)
3324  {
3325  TActiveLevelCrossing TALC;
3326  TALC.ConsecSignals = Utilities->LoadFileInt(VecFile); //changed to int from bool in v2.6.0
3327  TALC.ReducedTimePenalty = Utilities->LoadFileBool(VecFile);
3328  TALC.BarrierState = TBarrierState(Utilities->LoadFileInt(VecFile));
3329  TALC.ChangeDuration = Utilities->LoadFileDouble(VecFile);
3330  TALC.BaseElementSpeedTag = Utilities->LoadFileInt(VecFile);
3331  TALC.HLoc = Utilities->LoadFileInt(VecFile);
3332  TALC.VLoc = Utilities->LoadFileInt(VecFile);
3333  TALC.StartTime = TDateTime(Utilities->LoadFileDouble(VecFile));
3334  BarriersDownVector.push_back(TALC);
3335  }
3336  Utilities->CallLogPop(1979);
3337 }
3338 
3339 // ---------------------------------------------------------------------------
3340 
3341 void TTrack::RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
3342 /*
3343  Note, have to plot inactives before track because track has to overwrite NamedNonStationLocations, but, plot basic LC's (if flag set) after track
3344  so they lie above the track. Basic LCs are plotted for all but Level1Mode == OperMode (i.e. closed to trains), because the LC attributes will always be
3345  0 in such cases and because in OperMode the LCs have to be plotted again after the routes, which is done in Clearand....
3346 */
3347 {
3348  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildTrackAndText," + AnsiString((short)BothPointFilletsAndBasicLCs));
3349  TTrackElement Next;
3350 
3351 // Disp->ClearDisplay();
3353  while(ReturnNextInactiveTrackElement(0, Next))
3354  {
3355  if(Next.TrackType != LevelCrossing) // don't plot level crossings as these need to be plotted after the track
3356  {
3357  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3358  {
3359  // only plot if on screen, to save time
3360  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3362  {
3363  Next.PlotVariableTrackElement(2, Disp); // striped if not named
3364  }
3365  }
3366  }
3367  }
3368 
3369  TextHandler->RebuildFromTextVector(1, Disp); // plot text after inactives so can have text on stations etc
3370 
3371  NextTrackElementPtr = TrackVector.begin();
3372  while(ReturnNextTrackElement(0, Next))
3373  {
3374  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3375  {
3376  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3378  {
3379  if(Next.TrackType == Points)
3380  PlotPoints(5, Next, Disp, BothPointFilletsAndBasicLCs);
3381  else if(Next.TrackType == SignalPost)
3382  PlotSignal(9, Next, Disp);
3383  else if(Next.TrackType == GapJump)
3384  PlotGap(0, Next, Disp);
3385  else
3386  Next.PlotVariableTrackElement(3, Disp); // for footcrossings, may be striped or not
3387  }
3388  }
3389  }
3390 
3391  if(BothPointFilletsAndBasicLCs)
3392  {
3394  while(ReturnNextInactiveTrackElement(4, Next))
3395  {
3396  if(Next.TrackType == LevelCrossing) // plot level crossings (if required) after the track
3397  {
3398  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3399  {
3400  // only plot if on screen, to save time, & OK as plotting one by one here
3401  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3403  {
3404  if(GetTrackElementFromTrackMap(1, Next.HLoc, Next.VLoc).SpeedTag == 1)
3405  {
3406  Disp->PlotOutput(193, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothVer);
3407  }
3408  else
3409  {
3410  Disp->PlotOutput(194, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothHor);
3411  }
3412  }
3413  }
3414  }
3415  }
3416  }
3417  Disp->Update();
3418  Utilities->CallLogPop(468);
3419 }
3420 
3421 // ---------------------------------------------------------------------------
3422 
3423 void TTrack::RebuildUserGraphics(int Caller, TDisplay *Disp) // new at v2.4.0
3424 {
3425  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildUserGraphics,");
3426  if(UserGraphicVector.empty())
3427  {
3428  Utilities->CallLogPop(2175);
3429  return;
3430  }
3431  TUserGraphicItem UGI;
3432 
3433  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
3434  {
3435  UGI = UserGraphicVectorAt(4, x);
3436  if(((UGI.HPos + UGI.Width - (Display->DisplayOffsetH * 16)) >= 0) && ((UGI.HPos - (Display->DisplayOffsetH * 16)) <
3437  (Utilities->ScreenElementWidth * 16)) && ((UGI.VPos + UGI.Height - (Display->DisplayOffsetV * 16)) >= 0) &&
3438  ((UGI.VPos - (Display->DisplayOffsetV * 16)) < (Utilities->ScreenElementHeight * 16)))
3439  {
3440  Disp->PlotAndAddUserGraphic(0, UGI);
3441  }
3442  }
3443  Disp->Update();
3444  Utilities->CallLogPop(2176);
3445 }
3446 
3447 // ---------------------------------------------------------------------------
3448 
3449 void TTrack::WriteTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
3450 /*
3451  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
3452 */
3453 {
3454  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteTrackToImage");
3455 // need to change graphics back to black on white if have a dark background
3456  TColor OldTransparentColour = Utilities->clTransparent;
3457 
3459  {
3460  Utilities->clTransparent = TColor(0xFFFFFF); // white
3463  }
3464  TTrackElement Next;
3465 
3466  Bitmap->Canvas->CopyMode = cmSrcCopy;
3468  Graphics::TBitmap *GraphicOutput;
3469 
3470  while(ReturnNextInactiveTrackElement(2, Next))
3471  {
3472  GraphicOutput = Next.GraphicPtr;
3473  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3474  {
3475  if(Next.LocationName == "") // plot as named or unnamed (striped)
3476  { // default is not striped
3477  switch(Next.SpeedTag)
3478  {
3479  case 76: // t platform
3480  GraphicOutput = RailGraphics->gl76Striped;
3481  break;
3482 
3483  case 77: // h platform
3484  GraphicOutput = RailGraphics->bm77Striped;
3485  break;
3486 
3487  case 78: // v platform
3488  GraphicOutput = RailGraphics->bm78Striped;
3489  break;
3490 
3491  case 79: // r platform
3492  GraphicOutput = RailGraphics->gl79Striped;
3493  break;
3494 
3495  case 96: // concourse
3496  GraphicOutput = RailGraphics->ConcourseStriped;
3497  break;
3498 
3499  case 129: // v footbridge
3500  GraphicOutput = RailGraphics->gl129Striped;
3501  break;
3502 
3503  case 130: // h footbridge
3504  GraphicOutput = RailGraphics->gl130Striped;
3505  break;
3506 
3507  case 131: // non-station named loc
3508  GraphicOutput = RailGraphics->bmNameStriped;
3509  break;
3510 
3511  case 145: // v underpass
3512  GraphicOutput = RailGraphics->gl145Striped;
3513  break;
3514 
3515  case 146: // h underpass
3516  GraphicOutput = RailGraphics->gl146Striped;
3517  break;
3518 
3519  default:
3520  GraphicOutput = Next.GraphicPtr;
3521  break;
3522  }
3523  }
3524  if(Next.SpeedTag == 144) // level crossing
3525  {
3526  if(GetTrackElementFromTrackMap(2, Next.HLoc, Next.VLoc).SpeedTag == 1)
3527  {
3528  GraphicOutput = RailGraphics->LCBothVer;
3529  }
3530  else
3531  {
3532  GraphicOutput = RailGraphics->LCBothHor;
3533  }
3534  }
3535  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
3536  }
3537  }
3538 
3539  NextTrackElementPtr = TrackVector.begin();
3540  while(ReturnNextTrackElement(2, Next))
3541  {
3542  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3543  {
3544  if(Next.TrackType == Points) // plot both fillets
3545  {
3546  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3547  if(Next.SpeedTag < 28)
3548  {
3549  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3551  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3553  }
3554  else if(Next.SpeedTag < 132)
3555  {
3556  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3557  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][0]);
3558  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3559  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][1]);
3560  }
3561  else
3562  {
3563  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3564  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][0]);
3565  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3566  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][1]);
3567  }
3568  }
3569  else if(Next.TrackType == GapJump) // plot as connected or unconnected
3570  {
3571  if((Next.SpeedTag == 88) && (Next.Conn[0] > -1))
3572  {
3573  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
3574  }
3575  else if((Next.SpeedTag == 88) && (Next.Conn[0] == -1))
3576  {
3577  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88unset);
3578  }
3579  if((Next.SpeedTag == 89) && (Next.Conn[0] > -1))
3580  {
3581  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
3582  }
3583  else if((Next.SpeedTag == 89) && (Next.Conn[0] == -1))
3584  {
3585  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89unset);
3586  }
3587  if((Next.SpeedTag == 90) && (Next.Conn[0] > -1))
3588  {
3589  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
3590  }
3591  else if((Next.SpeedTag == 90) && (Next.Conn[0] == -1))
3592  {
3593  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90unset);
3594  }
3595  if((Next.SpeedTag == 91) && (Next.Conn[0] > -1))
3596  {
3597  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
3598  }
3599  else if((Next.SpeedTag == 91) && (Next.Conn[0] == -1))
3600  {
3601  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91unset);
3602  }
3603  if((Next.SpeedTag == 92) && (Next.Conn[0] > -1))
3604  {
3605  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
3606  }
3607  else if((Next.SpeedTag == 92) && (Next.Conn[0] == -1))
3608  {
3609  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92unset);
3610  }
3611  if((Next.SpeedTag == 93) && (Next.Conn[0] > -1))
3612  {
3613  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
3614  }
3615  else if((Next.SpeedTag == 93) && (Next.Conn[0] == -1))
3616  {
3617  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93unset);
3618  }
3619  if((Next.SpeedTag == 94) && (Next.Conn[0] > -1))
3620  {
3621  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
3622  }
3623  else if((Next.SpeedTag == 94) && (Next.Conn[0] == -1))
3624  {
3625  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94unset);
3626  }
3627  if((Next.SpeedTag == 95) && (Next.Conn[0] > -1))
3628  {
3629  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
3630  }
3631  else if((Next.SpeedTag == 95) && (Next.Conn[0] == -1))
3632  {
3633  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95unset);
3634  }
3635  }
3636  // below added for version 0.6, only stop signals to be drawn
3637  else if(Next.TrackType == SignalPost)
3638  {
3639  for(int x = 0; x < 40; x++)
3640  {
3641  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 0)) // need to plot as red regardless of actual attribute value
3642  {
3643  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
3644  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
3645  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
3646  int HOffset = 0;
3647  if(Next.SpeedTag > 73)
3648  HOffset = 5;
3649  else if(Next.SpeedTag == 71)
3650  HOffset = 9;
3651  int VOffset = 0;
3652  if(Next.SpeedTag == 69)
3653  VOffset = 9;
3654  else if(Next.SpeedTag == 72)
3655  VOffset = 5;
3656  else if(Next.SpeedTag == 74)
3657  VOffset = 5;
3658  Graphics::TBitmap *GraphicPtr;
3659  if(Next.SpeedTag > 71)
3660  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
3661  else if(Next.SpeedTag < 70)
3662  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
3663  else
3664  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
3665  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
3666  // plot special signal platform if present
3667  Graphics::TBitmap* SignalPlatformGraphic;
3668  if(PlatformOnSignalSide(2, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic)) //
3669  {
3670  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
3671  }
3672  // now plot signal (double yellow overwrites most of signal platform if present)
3673  // below amended for version 0.6
3675  {
3676  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
3677  }
3678  else if(Next.SigAspect == TTrackElement::TwoAspect)
3679  {
3680  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
3681  }
3682  else if(Next.SigAspect == TTrackElement::GroundSignal)
3683  {
3684  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
3685  }
3686  else // 4 aspect
3687  {
3688  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
3689  }
3690  break;
3691  }
3692  }
3693  }
3694  else
3695  {
3696  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3697  }
3698  }
3699  }
3700  if(OldTransparentColour != clB5G5R5)
3701  {
3702  Utilities->clTransparent = OldTransparentColour; // restore
3705  }
3706  Utilities->CallLogPop(1533);
3707 }
3708 
3709 // ---------------------------------------------------------------------------
3710 
3711 void TTrack::WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
3712 {
3713  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteGraphicsToImage");
3714  if(UserGraphicVector.empty())
3715  {
3716  Utilities->CallLogPop(2192);
3717  return;
3718  }
3719  else
3720  {
3721  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
3722  {
3723  Bitmap->Canvas->CopyMode = cmSrcCopy;
3724  Bitmap->Canvas->Draw(UserGraphicVectorAt(26, x).HPos - (GetHLocMin() * 16), UserGraphicVectorAt(27, x).VPos - (GetVLocMin() * 16),
3725  UserGraphicVectorAt(28, x).UserGraphic->Graphic);
3726  }
3727  }
3728  Utilities->CallLogPop(2193);
3729 }
3730 
3731 // ---------------------------------------------------------------------------
3732 
3733 void TTrack::WriteOperatingTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
3734 /*
3735  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
3736  Here plot all named elements as non-striped, points with active fillet, signals as they are set, and gaps as connected
3737 */
3738 {
3739  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteOperatingTrackToImage");
3740 // need to change graphics back to black on white if have a dark background
3741  TColor OldTransparentColour = Utilities->clTransparent;
3742 
3744  {
3745  Utilities->clTransparent = TColor(0xFFFFFF); // white
3748  }
3749  TTrackElement Next;
3750 
3751  Bitmap->Canvas->CopyMode = cmSrcCopy;
3753  Graphics::TBitmap *GraphicOutput;
3754 
3755  while(ReturnNextInactiveTrackElement(3, Next))
3756  {
3757  GraphicOutput = Next.GraphicPtr; // no striped name graphics
3758  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3759  {
3760  if(Next.SpeedTag == 144) // level crossing
3761  {
3762  int BaseElement = GetTrackElementFromTrackMap(3, Next.HLoc, Next.VLoc).SpeedTag;
3763  if(BaseElement == 1) // hor element
3764  {
3765  if(Next.Attribute == 1) // open to trains
3766  {
3767  GraphicOutput = RailGraphics->LCBothHor;
3768  }
3769  else // plot as closed to trains if in any other state
3770  {
3771  GraphicOutput = RailGraphics->LCBothVer;
3772  }
3773  }
3774  else // vert element
3775  {
3776  if(Next.Attribute == 1) // open to trains
3777  {
3778  GraphicOutput = RailGraphics->LCBothVer;
3779  }
3780  else // plot as closed to trains if in any other state
3781  {
3782  GraphicOutput = RailGraphics->LCBothHor;
3783  }
3784  }
3785  }
3786  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
3787  }
3788  }
3789 
3790  NextTrackElementPtr = TrackVector.begin();
3791  while(ReturnNextTrackElement(3, Next))
3792  {
3793  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3794  {
3795  if(Next.TrackType == Points) // plot active fillet
3796  {
3797  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3798  if(Next.SpeedTag < 28)
3799  {
3800  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3802  }
3803  else if(Next.SpeedTag < 132)
3804  {
3805  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3807  }
3808  else
3809  {
3810  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3812  }
3813  }
3814  else if(Next.TrackType == GapJump) // plot as connected
3815  {
3816  if(Next.SpeedTag == 88)
3817  {
3818  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
3819  }
3820  else if(Next.SpeedTag == 89)
3821  {
3822  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
3823  }
3824  else if(Next.SpeedTag == 90)
3825  {
3826  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
3827  }
3828  else if(Next.SpeedTag == 91)
3829  {
3830  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
3831  }
3832  else if(Next.SpeedTag == 92)
3833  {
3834  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
3835  }
3836  else if(Next.SpeedTag == 93)
3837  {
3838  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
3839  }
3840  else if(Next.SpeedTag == 94)
3841  {
3842  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
3843  }
3844  else if(Next.SpeedTag == 95)
3845  {
3846  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
3847  }
3848  }
3849  else if(Next.TrackType == SignalPost) // plot in correct colour
3850  {
3851  for(int x = 0; x < 40; x++)
3852  {
3853  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == Next.Attribute))
3854  {
3855  // plot blank first, then plot platform if present - (always not striped for operating railway)
3856  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
3857  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
3858  int HOffset = 0;
3859  if(Next.SpeedTag > 73)
3860  HOffset = 5;
3861  else if(Next.SpeedTag == 71)
3862  HOffset = 9;
3863  int VOffset = 0;
3864  if(Next.SpeedTag == 69)
3865  VOffset = 9;
3866  else if(Next.SpeedTag == 72)
3867  VOffset = 5;
3868  else if(Next.SpeedTag == 74)
3869  VOffset = 5;
3870  Graphics::TBitmap *GraphicPtr;
3871  if(Next.SpeedTag > 71)
3872  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
3873  else if(Next.SpeedTag < 70)
3874  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
3875  else
3876  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
3877  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
3878  // plot special signal platform if present
3879  Graphics::TBitmap* SignalPlatformGraphic;
3880  if(PlatformOnSignalSide(1, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
3881  {
3882  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
3883  }
3884  // now plot signal (double yellow overwrites most of signal platform if present)
3885  // below amended for version 0.6
3887  {
3888  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
3889  }
3890  else if(Next.SigAspect == TTrackElement::TwoAspect)
3891  {
3892  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
3893  }
3894  else if(Next.SigAspect == TTrackElement::GroundSignal)
3895  {
3896  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
3897  }
3898  else // 4 aspect
3899  {
3900  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
3901  }
3902  if((Next.CallingOnSet) && (Next.SigAspect != TTrackElement::GroundSignal))
3903  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
3904  {
3905  if(Next.SpeedTag == 68)
3906  {
3907  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm68CallingOn);
3908  }
3909  if(Next.SpeedTag == 69)
3910  {
3911  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm69CallingOn);
3912  }
3913  if(Next.SpeedTag == 70)
3914  {
3915  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm70CallingOn);
3916  }
3917  if(Next.SpeedTag == 71)
3918  {
3919  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm71CallingOn);
3920  }
3921  if(Next.SpeedTag == 72)
3922  {
3923  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm72CallingOn);
3924  }
3925  if(Next.SpeedTag == 73)
3926  {
3927  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm73CallingOn);
3928  }
3929  if(Next.SpeedTag == 74)
3930  {
3931  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm74CallingOn);
3932  }
3933  if(Next.SpeedTag == 75)
3934  {
3935  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm75CallingOn);
3936  }
3937  }
3938  else if((Next.CallingOnSet) && (Next.SigAspect == TTrackElement::GroundSignal)) // ground signal calling on, use normal proceed aspect
3939  {
3940  for(int x = 0; x < 40; x++)
3941  {
3942  if((SigTableGroundSignal[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
3943  {
3944  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
3945  Display->PlotSignalBlankOnBitmap(Next.HLoc - GetHLocMin(), Next.VLoc - GetVLocMin(), Next.SpeedTag, Bitmap,
3946  Utilities->RHSignalFlag); // in case existing signal is a double yellow
3947  // plot special signal platform if present
3948  Graphics::TBitmap* SignalPlatformGraphic;
3949  if(PlatformOnSignalSide(4, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
3950  {
3951  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
3952  }
3953  // now plot signal
3954  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
3955  break;
3956  }
3957  }
3958  }
3959  break;
3960  }
3961  }
3962  }
3963  else
3964  {
3965  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3966  }
3967  }
3968  }
3969  if(OldTransparentColour != clB5G5R5)
3970  {
3971  Utilities->clTransparent = OldTransparentColour; // restore
3974  }
3975  Utilities->CallLogPop(1701);
3976 }
3977 
3978 // ---------------------------------------------------------------------------
3979 
3980 bool TTrack::FindAndHighlightAnUnsetGap(int Caller) // true if find one
3981 {
3982  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindAndHighlightAnUnsetGap");
3983  for(unsigned int x = 0; x < TrackVector.size(); x++)
3984  {
3985  if(TrackVector.at(x).TrackType == GapJump)
3986  {
3987  if(TrackVector.at(x).Conn[0] > -1)
3988  continue; // to next 'x' value as this element has already been set
3989  // here if identify a GapJump element not yet set
3990  GapPos = x;
3991  GapHLoc = TrackVector.at(x).HLoc;
3992  GapVLoc = TrackVector.at(x).VLoc;
3993  // highlight it
3995  Utilities->CallLogPop(469);
3996  return true;
3997  }
3998  }
3999  Utilities->CallLogPop(470);
4000  return false;
4001 }
4002 
4003 // ---------------------------------------------------------------------------
4004 
4005 bool TTrack::FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc) // true if find one
4006 {
4007  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindSetAndDisplayMatchingGap," + AnsiString(HLoc) + "," +
4008  AnsiString(VLoc));
4009  int Position;
4010  TTrackElement TrackElement;
4011 
4012  if(!(FindNonPlatformMatch(11, HLoc, VLoc, Position, TrackElement)))
4013  {
4014  Utilities->CallLogPop(471);
4015  return false; // not found
4016  }
4017  if(TrackElement.TrackType != GapJump)
4018  {
4019  Utilities->CallLogPop(472);
4020  return false; // found something but not a gap
4021  }
4022  if(Position == GapPos)
4023  {
4024  Utilities->CallLogPop(473);
4025  return false; // selected original gap
4026  }
4027  if(TrackVector.at(Position).Conn[0] != -1)
4028  {
4029  Utilities->CallLogPop(474);
4030  return false; // already selected
4031  }
4032  TrackVector.at(Position).Conn[0] = GapPos; // set Conn[0] at Position to GapPos & ConnLinkPos[0] to 0
4033  TrackVector.at(Position).ConnLinkPos[0] = 0;
4034  TrackVector.at(GapPos).Conn[0] = Position; // set other one similarly
4035  TrackVector.at(GapPos).ConnLinkPos[0] = 0;
4036 // now highlight the selected location
4037  Display->Ellipse(0, HLoc * 16, VLoc * 16, clB0G5R0);
4038  Utilities->CallLogPop(475);
4039  return true;
4040 }
4041 
4042 // ---------------------------------------------------------------------------
4043 
4044 bool TTrack::GapsUnset(int Caller)
4045  // returns true if there are gaps and any are unset
4046 {
4047  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GapsUnset");
4048  if(TrackVector.size() == 0)
4049  {
4050  Utilities->CallLogPop(476);
4051  return false;
4052  }
4053  for(unsigned int x = 0; x < TrackVector.size(); x++)
4054  {
4055  if(TrackVector.at(x).TrackType == GapJump)
4056  {
4057  if(TrackVector.at(x).Conn[0] == -1) // unset if -1 (Gap always at position 0)
4058  {
4059  Utilities->CallLogPop(477);
4060  return true;
4061  }
4062  else // set, but may not have matching element, or that element may not be set
4063  {
4064  if(TrackVector.at(TrackVector.at(x).Conn[0]).TrackType != GapJump)
4065  // check that the element pointed to by the gap link is a GapJump
4066  {
4067  ShowMessage("Error - gap connected to a non-gap. Railway file is corrupt, further use may cause a system crash");
4068  Utilities->CallLogPop(1137);
4069  return false;
4070  }
4071 // here if gap connection is itself a GapJump
4072  if(TrackVector.at(TrackVector.at(x).Conn[0]).Conn[0] != (int)x)
4073  // check that the element pointed to by the gap link is a GapJump & that its gap link
4074  // points back to 'x'
4075  {
4076  Utilities->CallLogPop(478);
4077  return true;
4078  }
4079 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4080  }
4081  } // if(TrackVector.at(x).TrackType == GapJump)
4082  } // for x...
4083  Utilities->CallLogPop(479);
4084  return false;
4085 }
4086 
4087 // ---------------------------------------------------------------------------
4088 
4089 bool TTrack::NoGaps(int Caller) // returns true if there are no gaps
4090 {
4091  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoGaps");
4092  for(unsigned int x = 0; x < TrackVector.size(); x++)
4093  {
4094  if(TrackVector.at(x).TrackType == GapJump)
4095  {
4096  Utilities->CallLogPop(1105);
4097  return false;
4098  }
4099  }
4100  Utilities->CallLogPop(1106);
4101  return true;
4102 }
4103 
4104 // ---------------------------------------------------------------------------
4105 
4106 bool TTrack::NoNamedLocationElements(int Caller) // returns true if there are no NamedLocationElements (includes footcrossings)
4107 {
4108  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoLocations");
4109  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4110  {
4111  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
4112  {
4113  Utilities->CallLogPop(1107);
4114  return false;
4115  }
4116  }
4117  for(unsigned int x = 0; x < TrackVector.size(); x++)
4118  {
4119  if(TrackVector.at(x).FixedNamedLocationElement)
4120  {
4121  Utilities->CallLogPop(1108);
4122  return false;
4123  }
4124  }
4125  Utilities->CallLogPop(1109);
4126  return true;
4127 }
4128 
4129 // ---------------------------------------------------------------------------
4130 
4132  // returns true if there are unnamed NamedLocationElements (includes footcrossings)
4133  // returns false otherwise or if there are no NamedLocationElements
4134 {
4135  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationsNotNamed");
4136  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4137  {
4138  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
4139  {
4140  if(InactiveTrackVector.at(x).LocationName == "")
4141  {
4142  Utilities->CallLogPop(1110);
4143  return true;
4144  }
4145  }
4146  }
4147  for(unsigned int x = 0; x < TrackVector.size(); x++)
4148  {
4149  if(TrackVector.at(x).FixedNamedLocationElement)
4150  {
4151  if(TrackVector.at(x).LocationName == "")
4152  {
4153  Utilities->CallLogPop(1111);
4154  return true;
4155  }
4156  }
4157  }
4158  Utilities->CallLogPop(1112);
4159  return false;
4160 }
4161 
4162 // ---------------------------------------------------------------------------
4163 
4164 void TTrack::ShowSelectedGap(int Caller, TDisplay *Disp)
4165 {
4166  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ShowSelectedGap,");
4167  Disp->Ellipse(1, GapHLoc * 16, GapVLoc * 16, clB0G0R5);
4168  Utilities->CallLogPop(480);
4169 }
4170 
4171 // ---------------------------------------------------------------------------
4172 
4174 {
4175  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAnyNonMatchingGaps");
4176  if(TrackVector.size() == 0)
4177  {
4178  Utilities->CallLogPop(481);
4179  return;
4180  }
4181  for(unsigned int x = 0; x < TrackVector.size(); x++)
4182  {
4183  if(TrackVector.at(x).TrackType == GapJump)
4184  {
4185  if(TrackVector.at(x).Conn[0] > -1) // set
4186  {
4187  if(TrackVector.at(TrackVector.at(x).Conn[0]).TrackType != GapJump)
4188  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks
4189  {
4190  TrackVector.at(x).Conn[0] = -1;
4191  TrackVector.at(x).ConnLinkPos[0] = -1;
4192  continue; // to next 'x'
4193  }
4194 // here if gap connection is itself a GapJump
4195  if(TrackVector.at(TrackVector.at(x).Conn[0]).Conn[0] != (int)x)
4196  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
4197  // if not clear Conns & CLks
4198  {
4199  TrackVector.at(x).Conn[0] = -1;
4200  TrackVector.at(x).ConnLinkPos[0] = -1;
4201  continue; // to next 'x'
4202  }
4203 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4204 // hence no more action needed on these Conns & CLks
4205  }
4206  } // else //gap jump
4207  } // for x...
4208 // throw Exception("Test Exception");//test
4209  Utilities->CallLogPop(482);
4210 }
4211 
4212 // ---------------------------------------------------------------------------
4213 
4214 void TTrack::ResetSignals(int Caller)
4215 {
4216  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetSignals");
4217  for(unsigned int x = 0; x < TrackVector.size(); x++)
4218  {
4219  if(TrackVector.at(x).TrackType == SignalPost)
4220  {
4221  TrackVector.at(x).Attribute = 0;
4222  }
4223  }
4224  Utilities->CallLogPop(483);
4225 }
4226 
4227 // ---------------------------------------------------------------------------
4228 
4229 void TTrack::ResetPoints(int Caller)
4230 {
4231  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetPoints");
4232  for(unsigned int x = 0; x < TrackVector.size(); x++)
4233  {
4234  if(TrackVector.at(x).TrackType == Points)
4235  {
4236  TrackVector.at(x).Attribute = 0;
4237  }
4238  }
4239  Utilities->CallLogPop(484);
4240 }
4241 
4242 // ---------------------------------------------------------------------------
4243 
4244 bool TTrack::RepositionAndMapTrack(int Caller) // doesn't involve InactiveTrack
4245 {
4246  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RepositionAndMapTrack");
4247  if(TrackVector.empty())
4248  {
4249  TrackMap.clear();
4250  Utilities->CallLogPop(485);
4251  return true;
4252  }
4253 
4254 // build new vector from map (map already in ascending order of locations & no erase elements in map)
4255  THVPair TrackMapKeyPair;
4256 
4257  NewVector.clear();
4258  TTrackMapIterator TrackMapPtr;
4259 
4260  if(!TrackMap.empty())
4261  {
4262  for(TrackMapPtr = TrackMap.begin(); TrackMapPtr != TrackMap.end(); TrackMapPtr++)
4263  {
4264  NewVector.push_back(TrackElementAt(6, TrackMapPtr->second));
4265  }
4266  }
4267  if(NewVector.size() != TrackMap.size())
4268  {
4269  throw Exception("Error - Map & Vector different sizes");
4270  }
4271  unsigned int NonZeroCount = 0;
4272 
4273  for(unsigned int x = 0; x < TrackVector.size(); x++)
4274  {
4275  if(TrackVector.at(x).TrackType != Erase)
4276  NonZeroCount++;
4277  }
4278  if(NewVector.size() != NonZeroCount)
4279  {
4280  throw Exception("Error - NewVector & NonZero TrackVector different sizes");
4281  }
4282 
4284  TrackMap.clear(); // ready to rebuild map after repositioning of TrackVector elements
4285  TTrackMapEntry TrackMapEntry;
4286 
4287  for(unsigned int x = 0; x < TrackVector.size(); x++)
4288  {
4289  TrackMapKeyPair.first = TrackVector.at(x).HLoc;
4290  TrackMapKeyPair.second = TrackVector.at(x).VLoc;
4291  TrackMapEntry.first = TrackMapKeyPair;
4292  TrackMapEntry.second = x;
4293  if(!(TrackMap.insert(TrackMapEntry).second))
4294  {
4295  throw Exception("Error - map insertion failure, TrackVector in error");
4296  }
4297  }
4298 // All track now relocated in TrackVector, reset all Conns & CLks
4299  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4300  {
4301  for(unsigned int y = 0; y < 4; y++)
4302  {
4303  TrackVector.at(x).Conn[y] = -1;
4304  TrackVector.at(x).ConnLinkPos[y] = -1;
4305  }
4306  }
4307  RebuildLocationNameMultiMap(1); // to ensure all position entries correct after track vector changes
4308  CheckMapAndTrack(4); // test
4309  CheckMapAndInactiveTrack(4); // test
4310  CheckLocationNameMultiMap(8); // test
4311  if(!ResetGapsFromGapMap(1))
4312  {
4313  Utilities->CallLogPop(489);
4314  return false;
4315  }
4316  Utilities->CallLogPop(490);
4317  return true;
4318 }
4319 
4320 // ---------------------------------------------------------------------------
4321 
4322 void TTrack::BuildGapMapFromTrackVector(int Caller) // Map contains one entry for each pair of matched gaps
4323 {
4324  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildGapMapFromTrackVector");
4325  GapMap.clear();
4326  THVPair GapMapKeyPair, GapMapValuePair;
4327  TGapMapEntry GapMapEntry;
4328 
4329  for(unsigned int x = 0; x < TrackVector.size(); x++)
4330  {
4331  if(TrackVector.at(x).TrackType == GapJump)
4332  {
4333  GapMapKeyPair.first = TrackVector.at(x).HLoc;
4334  GapMapKeyPair.second = TrackVector.at(x).VLoc;
4335  GapMapEntry.first = GapMapKeyPair;
4336  if(TrackVector.at(x).Conn[0] == -1)
4337  {
4338  throw Exception("Error - Gap connection == -1 Can't build GapMap");
4339  }
4340  GapMapValuePair.first = TrackElementAt(7, TrackVector.at(x).Conn[0]).HLoc;
4341  GapMapValuePair.second = TrackElementAt(8, TrackVector.at(x).Conn[0]).VLoc;
4342  GapMapEntry.second = GapMapValuePair;
4343  if(GapMap.find(GapMapValuePair) == GapMap.end()) // if ValuePair already included as a key then result won't be end()
4344  {
4345  GapMap.insert(GapMapEntry);
4346  }
4347  }
4348  }
4349  Utilities->CallLogPop(492);
4350 }
4351 
4352 // ---------------------------------------------------------------------------
4353 
4354 bool TTrack::LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
4355 {
4356  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrack," + AnsiString((short)FinalCall));
4357  LocError = false;
4358  bool CheckForLinks = false;
4359 
4360  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4361  {
4362  if(TrackVector.at(x).TrackType == Erase) //Erase isn't used any more as a track type
4363  continue; // skip blank elements
4364 // check footcrossing linkages
4365  if(TrackVector.at(x).TrackType == FootCrossing)
4366  {
4367  if(!CheckFootCrossingLinks(1, TrackVector.at(x)))
4368  {
4369  ShowMessage(
4370  "Footbridge or underpass connection error. Each end must connect to a platform, concourse or other footbridge or underpass, and they can't connect to each other");
4371  HLoc = TrackVector.at(x).HLoc;
4372  VLoc = TrackVector.at(x).VLoc;
4373  LocError = true;
4374  Utilities->CallLogPop(493);
4375  return false;
4376  }
4377  }
4378  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4379  {
4380  CheckForLinks = false;
4381  if(TrackVector.at(x).Link[y] <= 0)
4382  continue; // no link
4383  if((TrackVector.at(x).TrackType == Buffers) && (TrackVector.at(x).Config[y] == End))
4384  continue; // buffer
4385  if(TrackVector.at(x).Config[y] == Gap)
4386  continue; // gaps set later from GapMap
4387 
4388  // get required H & V for track element joining link 'y'
4389  int NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
4390  int NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
4391  // find track element if present
4392  bool ConnectionFoundFlag;
4393  int VecPos = GetVectorPositionFromTrackMap(14, NewHLoc, NewVLoc, ConnectionFoundFlag);
4394  if((TrackVector.at(x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
4395  {
4396  ShowMessage("Can't have a track element adjacent to a continuation exit");
4397  HLoc = TrackVector.at(x).HLoc;
4398  VLoc = TrackVector.at(x).VLoc;
4399  LocError = true;
4400  if(FinalCall)
4401  {
4402  throw Exception("Error in final track linkage - continuation adjacent to another element");
4403  }
4404  Utilities->CallLogPop(1539);
4405  return false;
4406  }
4407  if((TrackVector.at(x).TrackType == Continuation) && (TrackVector.at(x).Config[y] == End))
4408  continue;
4409  if(ConnectionFoundFlag)
4410  {
4411  TrackVector.at(x).Conn[y] = VecPos;
4412  // find connecting link in the newly found track element if there is one & make buffer & adjacent signals check
4413  bool LinkFoundFlag = false;
4414  if((TrackVector.at(x).Config[1 - y] == Signal) && IsLCAtHV(50, TrackVector.at(VecPos).HLoc, TrackVector.at(VecPos).VLoc))
4415  { // new in v2.4.0 - Krizar (Kristian Zarebski) found this error
4416  ShowMessage("Can't have an exit signal next to a level crossing - it can cause the train to foul the crossing in some circumstances");
4417  // otherwise when single route element removed in front of train the LC will start to close and the train will crash
4418  }
4419  else if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover))
4420  && (TrackVector.at(VecPos).TrackType == Buffers))
4421  {
4422  ShowMessage("Can't have points, crossover or signal next to buffers - need room for a train without fouling");
4423  // need room for a train (2 elements) without fouling points or signals
4424  }
4425  else if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover) ||
4426  (TrackVector.at(x).TrackType == Bridge)) && (TrackVector.at(VecPos).TrackType == Continuation))
4427  {
4428  ShowMessage("Can't have points, crossover, bridge or signal next to a continuation - it can cause route setting problems");
4429  // route setting won't allow an end of route selection adjacent to an existing route, which would happen
4430  // if continuation next to a signal; also none of these can be a named location, and a continuation can
4431  // be named but needs the adjacent element named too
4432  }
4433  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == SignalPost) &&
4434  (TrackVector.at(x).SpeedTag == TrackVector.at(VecPos).SpeedTag))
4435  {
4436  ShowMessage("Can't have two same-direction signals adjacent to each other as there is no room for a train between them");
4437  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4438  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4439  }
4440  else if((TrackVector.at(x).Config[y] == Signal) && (TrackVector.at(VecPos).TrackType == Bridge) && !OverrideAndHideSignalBridgeMessage)
4441  {
4442  ShowMessage("Signal facing a bridge - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
4443  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4444  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4445  }
4446  else if(IsLCAtHV(45, TrackVector.at(x).HLoc, TrackVector.at(x).VLoc) && IsLCAtHV(46, TrackVector.at(VecPos).HLoc, TrackVector.at(VecPos).VLoc))
4447  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
4448  {
4449  ShowMessage("Can't have two level crossings adjacent to each other on the same track");
4450  }
4451  else
4452  CheckForLinks = true;
4453  if(CheckForLinks)
4454  {
4455  for(unsigned int a = 0; a < 4; a++)
4456  {
4457  if((TrackVector.at(VecPos).Link[a] == (10 - TrackVector.at(x).Link[y])) && (TrackVector.at(VecPos).Config[a] != End) &&
4458  (TrackVector.at(VecPos).Config[a] != Gap))
4459  {
4460  TrackVector.at(x).ConnLinkPos[y] = a;
4461  // note - this ensures that if the connecting element is a leading point
4462  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
4463  // (Points have the same link value for both [0] and [2])
4464  LinkFoundFlag = true;
4465  break; // stop after first find or will find later link for leading point
4466  }
4467  }
4468  }
4469  // if there isn't a corresponding link, or buffer check fails, set the invert values for the offending element
4470  if(!LinkFoundFlag)
4471  {
4472  HLoc = TrackVector.at(x).HLoc;
4473  VLoc = TrackVector.at(x).VLoc;
4474  LocError = true;
4475  if(FinalCall)
4476  {
4477  throw Exception("Error in final track linkage - invalid link");
4478  }
4479  Utilities->CallLogPop(494);
4480  return false;
4481  }
4482  }
4483  // if there isn't a connection set the invert values for the offending element
4484  else // if(ConnectionFoundFlag)
4485  {
4486  HLoc = TrackVector.at(x).HLoc;
4487  VLoc = TrackVector.at(x).VLoc;
4488  LocError = true;
4489  if(FinalCall)
4490  {
4491  throw Exception("Error in final track linkage - connection not found");
4492  }
4493  Utilities->CallLogPop(495);
4494  return false;
4495  }
4496  }
4497  } // for(unsigned int x=0;x<TrackVector.size();x++)
4498 
4499  if(FinalCall)
4501 
4502 // final check
4503  bool ConnErrorFlag = false;
4504 
4505  for(unsigned int x = 0; x < TrackVector.size(); x++)
4506  {
4507  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).Conn[0] == -1))
4508  ConnErrorFlag = true;
4509  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).Conn[1] == -1))
4510  ConnErrorFlag = true;
4511  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).Conn[2] == -1))
4512  ConnErrorFlag = true;
4513  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).Conn[3] == -1))
4514  ConnErrorFlag = true;
4515  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
4516  {
4517  if(TrackVector.at(x).ActiveTrackElementName == "")
4518  {
4519  if((TrackVector.at(x).StationEntryStopLinkPos1 != -1) || (TrackVector.at(x).StationEntryStopLinkPos2 != -1))
4520  {
4521  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
4522  }
4523  }
4524  }
4525  }
4526  if(ConnErrorFlag)
4527  {
4528  if(FinalCall)
4529  {
4530  throw Exception("ConnError in LinkTrack - Final");
4531  }
4532  else
4533  {
4534  throw Exception("ConnError in LinkTrack - Precheck");
4535  }
4536  }
4537 
4538  bool CLkErrorFlag = false;
4539 
4540  for(unsigned int x = 0; x < TrackVector.size(); x++)
4541  {
4542  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).ConnLinkPos[0] == -1))
4543  CLkErrorFlag = true;
4544  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).ConnLinkPos[1] == -1))
4545  CLkErrorFlag = true;
4546  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).ConnLinkPos[2] == -1))
4547  CLkErrorFlag = true;
4548  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).ConnLinkPos[3] == -1))
4549  CLkErrorFlag = true;
4550  }
4551 
4552  if(CLkErrorFlag)
4553  {
4554  if(FinalCall)
4555  {
4556  throw Exception("CLkError in LinkTrack - Final");
4557  }
4558  else
4559  {
4560  throw Exception("CLkError in LinkTrack - Precheck");
4561  }
4562  }
4563 
4564 // set element lengths to min of 20m
4565  for(unsigned int x = 0; x < TrackVector.size(); x++)
4566  {
4567  if(TrackVector.at(x).TrackType == Erase)
4568  continue; // skip blank elements
4569  if(TrackVector.at(x).Length01 < 20)
4570  TrackVector.at(x).Length01 = 20;
4571  if((TrackVector.at(x).Length23 < 20) && (TrackVector.at(x).Length23 != -1))
4572  TrackVector.at(x).Length23 = 20;
4573  }
4574 
4575  if(FinalCall) // ONLY at FinalCall, no point calling twice
4576  {
4577  CalcHLocMinEtc(3);
4578  }
4579  Utilities->CallLogPop(497);
4580  return true;
4581 }
4582 
4583 // ---------------------------------------------------------------------------
4584 
4585 bool TTrack::LinkTrackNoMessages(int Caller, bool FinalCall)
4586 {
4587  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrackNoMessages," + AnsiString((short)FinalCall));
4588  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4589  {
4590  if(TrackVector.at(x).TrackType == Erase)
4591  continue; // skip blank elements
4592 
4593 // check footcrossing linkages
4594  if(TrackVector.at(x).TrackType == FootCrossing)
4595  {
4596  if(!CheckFootCrossingLinks(3, TrackVector.at(x)))
4597  {
4598  Utilities->CallLogPop(1127);
4599  return false;
4600  }
4601  }
4602 
4603  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4604  {
4605  if(TrackVector.at(x).Link[y] <= 0)
4606  continue; // no link
4607  if((TrackVector.at(x).TrackType == Buffers) && (TrackVector.at(x).Config[y] == End))
4608  continue; // buffer
4609  if(TrackVector.at(x).Config[y] == Gap)
4610  continue; // gaps set later from GapMap
4611 
4612  // get required H & V for track element joining link 'y'
4613  int NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
4614  int NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
4615  // find track element if present
4616  bool ConnectionFoundFlag;
4617  int VecPos = GetVectorPositionFromTrackMap(38, NewHLoc, NewVLoc, ConnectionFoundFlag);
4618  if((TrackVector.at(x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
4619  {
4620  if(FinalCall)
4621  {
4622  throw Exception("Error in final track linkage - continuation adjacent to another element");
4623  }
4624  Utilities->CallLogPop(1540);
4625  return false;
4626  }
4627  if((TrackVector.at(x).TrackType == Continuation) && (TrackVector.at(x).Config[y] == End))
4628  continue;
4629  if(ConnectionFoundFlag)
4630  {
4631  TrackVector.at(x).Conn[y] = VecPos;
4632  bool LinkFoundFlag = false;
4633  // find connecting link in the newly found track element if there is one & make checks
4634  if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover)) &&
4635  (TrackVector.at(VecPos).TrackType == Buffers))
4636  {
4637  Utilities->CallLogPop(1541);
4638  return false;
4639  }
4640  else if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover) ||
4641  (TrackVector.at(x).TrackType == Bridge)) && (TrackVector.at(VecPos).TrackType == Continuation))
4642  {
4643  Utilities->CallLogPop(1542);
4644  return false;
4645  }
4646  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == SignalPost) &&
4647  (TrackVector.at(x).SpeedTag == TrackVector.at(VecPos).SpeedTag))
4648  {
4649  Utilities->CallLogPop(1543);
4650  return false;
4651  }
4652  else if(IsLCAtHV(47, TrackVector.at(x).HLoc, TrackVector.at(x).VLoc) && IsLCAtHV(48, TrackVector.at(VecPos).HLoc, TrackVector.at(VecPos).VLoc))
4653  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
4654  {
4655  Utilities->CallLogPop(1981);
4656  return false;
4657  }
4658 /* remove this restriction now that not permitted to treat a named continuation as a location stop
4659  else if(TrackVector.at(x).TrackType == Continuation)
4660  {
4661  int H = TrackVector.at(x).HLoc;
4662  int V = TrackVector.at(x).VLoc;
4663  bool FoundFlag = false;
4664  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(18, H, V, FoundFlag);
4665  if(FoundFlag)
4666  {
4667  if(InactiveTrackElementAt(93, IMPair.first).TrackType == NamedNonStationLocation)
4668  {
4669  int NewH = TrackElementAt(727, (TrackVector.at(x).Conn[1])).HLoc;
4670  int NewV = TrackElementAt(728, (TrackVector.at(x).Conn[1])).VLoc;
4671  TIMPair NewIMPair = GetVectorPositionsFromInactiveTrackMap(19, NewH, NewV, FoundFlag);
4672  if(FoundFlag)
4673  {
4674  if(InactiveTrackElementAt(94, NewIMPair.first).TrackType != NamedNonStationLocation)
4675  {
4676  Utilities->CallLogPop(1544);
4677  return false;
4678  }
4679  }
4680  else
4681  {
4682  Utilities->CallLogPop(1545);
4683  return false;
4684  }
4685  }
4686  }
4687  }
4688 */
4689  for(unsigned int a = 0; a < 4; a++)
4690  {
4691  if((TrackVector.at(VecPos).Link[a] == (10 - TrackVector.at(x).Link[y])) && (TrackVector.at(VecPos).Config[a] != End) &&
4692  (TrackVector.at(VecPos).Config[a] != Gap))
4693  {
4694  TrackVector.at(x).ConnLinkPos[y] = a;
4695  // note - this ensures that if the connecting element is a leading point
4696  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
4697  // (Points have the same link value for both [0] and [2])
4698  LinkFoundFlag = true;
4699  break; // stop after first find or will find later link for leading point
4700  }
4701  }
4702  if(!LinkFoundFlag)
4703  {
4704  if(FinalCall)
4705  {
4706  throw Exception("Error in final track linkage in LinkTrackNoMessages - invalid link");
4707  }
4708  Utilities->CallLogPop(1128);
4709  return false;
4710  }
4711  }
4712  else // if(ConnectionFoundFlag)
4713  {
4714  if(FinalCall)
4715  {
4716  throw Exception("Error in final track linkage in LinkTrackNoMessages - connection not found");
4717  }
4718  Utilities->CallLogPop(1129);
4719  return false;
4720  }
4721  }
4722  } // for(unsigned int x=0;x<TrackVector.size();x++)
4723 
4724  if(FinalCall)
4726 
4727 // final check
4728  bool ConnErrorFlag = false;
4729 
4730  for(unsigned int x = 0; x < TrackVector.size(); x++)
4731  {
4732  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).Conn[0] == -1))
4733  ConnErrorFlag = true;
4734  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).Conn[1] == -1))
4735  ConnErrorFlag = true;
4736  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).Conn[2] == -1))
4737  ConnErrorFlag = true;
4738  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).Conn[3] == -1))
4739  ConnErrorFlag = true;
4740  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
4741  {
4742  if(TrackVector.at(x).ActiveTrackElementName == "")
4743  {
4744  if((TrackVector.at(x).StationEntryStopLinkPos1 != -1) || (TrackVector.at(x).StationEntryStopLinkPos2 != -1))
4745  {
4746  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
4747  }
4748  }
4749  }
4750  }
4751  if(ConnErrorFlag)
4752  {
4753  if(FinalCall)
4754  {
4755  throw Exception("ConnError in LinkTrack - Final");
4756  }
4757  else
4758  {
4759  throw Exception("ConnError in LinkTrack - Precheck");
4760  }
4761  }
4762 
4763  bool CLkErrorFlag = false;
4764 
4765  for(unsigned int x = 0; x < TrackVector.size(); x++)
4766  {
4767  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).ConnLinkPos[0] == -1))
4768  CLkErrorFlag = true;
4769  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).ConnLinkPos[1] == -1))
4770  CLkErrorFlag = true;
4771  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).ConnLinkPos[2] == -1))
4772  CLkErrorFlag = true;
4773  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).ConnLinkPos[3] == -1))
4774  CLkErrorFlag = true;
4775  }
4776 
4777  if(CLkErrorFlag)
4778  {
4779  if(FinalCall)
4780  {
4781  throw Exception("CLkError in LinkTrack - Final");
4782  }
4783  else
4784  {
4785  throw Exception("CLkError in LinkTrack - Precheck");
4786  }
4787  }
4788 
4789 // set element lengths to min of 20m
4790  for(unsigned int x = 0; x < TrackVector.size(); x++)
4791  {
4792  if(TrackVector.at(x).TrackType == Erase)
4793  continue; // skip blank elements
4794  if(TrackVector.at(x).Length01 < 20)
4795  TrackVector.at(x).Length01 = 20;
4796  if((TrackVector.at(x).Length23 < 20) && (TrackVector.at(x).Length23 != -1))
4797  TrackVector.at(x).Length23 = 20;
4798  }
4799 
4800  if(FinalCall) // ONLY at FinalCall, no point calling twice
4801  {
4802  CalcHLocMinEtc(7);
4803  }
4804  Utilities->CallLogPop(1130);
4805  return true;
4806 }
4807 
4808 // ---------------------------------------------------------------------------
4809 
4810 bool TTrack::IsTrackLinked(int Caller) // not used any more
4811 {
4812  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsTrackLinked");
4813  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4814  {
4815  if(TrackVector.at(x).TrackType == Erase)
4816  {
4817  Utilities->CallLogPop(498);
4818  return false;
4819  }
4820 
4821 // check foot linkages
4822  if(TrackVector.at(x).TrackType == FootCrossing)
4823  {
4824  if(!CheckFootCrossingLinks(2, TrackVector.at(x)))
4825  {
4826  Utilities->CallLogPop(499);
4827  return false;
4828  }
4829  }
4830 
4831  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4832  {
4833  if(TrackVector.at(x).Link[y] <= 0)
4834  continue; // no link
4835  if(TrackVector.at(x).Config[y] == End)
4836  continue; // buffer or continuation
4837  if(TrackVector.at(x).Config[y] == Gap)
4838  continue; // gaps set later from GapMap
4839 
4840  // get required H & V for track element joining link 'y'
4841  int NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
4842  int NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
4843  // find track element if present
4844  bool ConnectionFoundFlag = false;
4845  int VecPos = GetVectorPositionFromTrackMap(15, NewHLoc, NewVLoc, ConnectionFoundFlag);
4846  if(ConnectionFoundFlag)
4847  {
4848  TrackVector.at(x).Conn[y] = VecPos;
4849  // find connecting link in the newly found track element if there is one & make buffer check
4850  bool LinkFoundFlag = false;
4851  if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover)) &&
4852  (TrackVector.at(VecPos).TrackType == Buffers))
4853  {
4854  Utilities->CallLogPop(500);
4855  return false;
4856  }
4857  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == SignalPost) &&
4858  (TrackVector.at(x).SpeedTag == TrackVector.at(VecPos).SpeedTag))
4859  {
4860  Utilities->CallLogPop(501);
4861  return false;
4862  }
4863  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == Continuation))
4864  {
4865  Utilities->CallLogPop(502);
4866  return false;
4867  }
4868  else
4869  {
4870  for(unsigned int a = 0; a < 4; a++)
4871  {
4872  if((TrackVector.at(VecPos).Link[a] == (10 - TrackVector.at(x).Link[y])) && (TrackVector.at(VecPos).Config[a] != End) &&
4873  (TrackVector.at(VecPos).Config[a] != Gap))
4874  {
4875  TrackVector.at(x).ConnLinkPos[y] = a;
4876  // note - this ensures that if the connecting element is a leading point
4877  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
4878  // (Points have the same link value for both [0] and [2])
4879  LinkFoundFlag = true;
4880  break; // stop after first find or will find later link for leading point
4881  }
4882  }
4883  }
4884  if(!LinkFoundFlag)
4885  {
4886  Utilities->CallLogPop(503);
4887  return false;
4888  }
4889  }
4890  else // if(ConnectionFoundFlag)
4891  {
4892  Utilities->CallLogPop(504);
4893  return false;
4894  }
4895  }
4896  } // for(unsigned int x=0;x<TrackVector.size();x++)
4897 
4898 // final check
4899  bool ConnErrorFlag = false;
4900 
4901  for(unsigned int x = 0; x < TrackVector.size(); x++)
4902  {
4903  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).Conn[0] == -1))
4904  ConnErrorFlag = true;
4905  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).Conn[1] == -1))
4906  ConnErrorFlag = true;
4907  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).Conn[2] == -1))
4908  ConnErrorFlag = true;
4909  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).Conn[3] == -1))
4910  ConnErrorFlag = true;
4911  }
4912  if(ConnErrorFlag)
4913  {
4914  Utilities->CallLogPop(505);
4915  return false;
4916  }
4917 
4918  bool CLkErrorFlag = false;
4919 
4920  for(unsigned int x = 0; x < TrackVector.size(); x++)
4921  {
4922  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).ConnLinkPos[0] == -1))
4923  CLkErrorFlag = true;
4924  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).ConnLinkPos[1] == -1))
4925  CLkErrorFlag = true;
4926  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).ConnLinkPos[2] == -1))
4927  CLkErrorFlag = true;
4928  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).ConnLinkPos[3] == -1))
4929  CLkErrorFlag = true;
4930  }
4931 
4932  if(CLkErrorFlag)
4933  {
4934  Utilities->CallLogPop(506);
4935  return false;
4936  }
4937  Utilities->CallLogPop(507);
4938  return true;
4939 }
4940 
4941 // ---------------------------------------------------------------------------
4942 
4944 {
4945  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetGapsFromGapMap");
4946  int Position1, Position2;
4947  TTrackElement TrackElement1, TrackElement2;
4948  TGapMapIterator GapMapPtr;
4949 
4950  if(!GapMap.empty())
4951  {
4952  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
4953  {
4954  int HLoc1 = GapMapPtr->first.first;
4955  int VLoc1 = GapMapPtr->first.second;
4956  int HLoc2 = GapMapPtr->second.first;
4957  int VLoc2 = GapMapPtr->second.second;
4958  if(!FindNonPlatformMatch(12, HLoc1, VLoc1, Position1, TrackElement1))
4959  {
4960  throw Exception("Failed to find H & V for gap1, GapMap in error");
4961  }
4962  if(!FindNonPlatformMatch(13, HLoc2, VLoc2, Position2, TrackElement2))
4963  {
4964  throw Exception("Failed to find H & V for gap2, GapMap in error");
4965  }
4966  if(TrackElementAt(9, Position1).TrackType != GapJump)
4967  {
4968  throw Exception("Element at Pos1 not a gap, GapMap in error");
4969  }
4970  if(TrackElementAt(10, Position2).TrackType != GapJump)
4971  {
4972  throw Exception("Element at Pos2 not a gap, GapMap in error");
4973  }
4974  TrackElementAt(11, Position1).Conn[0] = Position2;
4975  TrackElementAt(12, Position1).ConnLinkPos[0] = 0;
4976  TrackElementAt(13, Position2).Conn[0] = Position1;
4977  TrackElementAt(14, Position2).ConnLinkPos[0] = 0;
4978  }
4979  }
4980  Utilities->CallLogPop(510);
4981  return true;
4982 }
4983 
4984 // ---------------------------------------------------------------------------
4985 
4986 void TTrack::TrackPush(int Caller, TTrackElement TrackElement)
4987 {
4988 // TIMPair MapEntry;
4989  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackPush," + AnsiString(TrackElement.HLoc) + "," +
4990  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
4991  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
4992  TTrackMapEntry TrackMapEntry, InactiveTrackMapEntry;
4993  TLocationNameMultiMapEntry LocationNameEntry;
4994 
4995  LocationNameEntry.first = TrackElement.LocationName;
4996  if((TrackElement.TrackType == Platform) || (TrackElement.TrackType == Concourse) || (TrackElement.TrackType == Parapet) ||
4997  (TrackElement.TrackType == NamedNonStationLocation) || (TrackElement.TrackType == LevelCrossing))
4998  {
4999 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5000 // could arise when loading old railways with multiple NonStationNamedLocs
5001  bool FoundFlag = false;
5002  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(20, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5003  if(FoundFlag)
5004  {
5005  if((InactiveTrackElementAt(97, IMPair.first).SpeedTag == TrackElement.SpeedTag) || (InactiveTrackElementAt(98,
5006  IMPair.second).SpeedTag == TrackElement.SpeedTag))
5007  {
5008  Utilities->CallLogPop(1813);
5009  return;
5010  }
5011  }
5012  InactiveTrackVector.push_back(TrackElement); // no erase elements involved in InactiveTrackVector
5013  InactiveTrackMapKeyPair.first = TrackElement.HLoc;
5014  InactiveTrackMapKeyPair.second = TrackElement.VLoc;
5015  InactiveTrackMapEntry.first = InactiveTrackMapKeyPair;
5016  InactiveTrackMapEntry.second = InactiveTrackVector.size() - 1;
5017  InactiveTrack2MultiMap.insert(InactiveTrackMapEntry);
5018  if(TrackElement.FixedNamedLocationElement)
5019  {
5020  LocationNameEntry.second = InactiveTrackVector.size() - 1; // add to LocationNameMultiMap
5021  LocationNameMultiMap.insert(LocationNameEntry);
5022  }
5023  if(TrackElement.HLoc < HLocMin)
5024  HLocMin = TrackElement.HLoc;
5025  if(TrackElement.HLoc > HLocMax)
5026  HLocMax = TrackElement.HLoc;
5027  if(TrackElement.VLoc < VLocMin)
5028  VLocMin = TrackElement.VLoc;
5029  if(TrackElement.VLoc > VLocMax)
5030  VLocMax = TrackElement.VLoc;
5031  }
5032  else
5033  {
5034 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5035 // shouldn't arise but leave in as a safeguard
5036  bool FoundFlag = false;
5037  int VecPos = GetVectorPositionFromTrackMap(44, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5038  if(FoundFlag)
5039  {
5040  if(TrackElementAt(816, VecPos).SpeedTag == TrackElement.SpeedTag)
5041  {
5042  Utilities->CallLogPop(1814);
5043  return;
5044  }
5045  }
5046  TrackVector.push_back(TrackElement); // add erase elements to vector to keep linkages correct (now dispensed with)
5047  if(TrackElement.TrackType != Erase) // don't add erase elements to TrackMap (dispensed with these but keep code)
5048  {
5049  TrackMapKeyPair.first = TrackElement.HLoc;
5050  TrackMapKeyPair.second = TrackElement.VLoc;
5051  TrackMapEntry.first = TrackMapKeyPair;
5052  TrackMapEntry.second = TrackVector.size() - 1;
5053  TrackMap.insert(TrackMapEntry);
5054  if(TrackElement.FixedNamedLocationElement)
5055  {
5056  LocationNameEntry.second = -(int)(TrackVector.size()); // add to LocationNameMultiMap TrackVector.size = Required value + 1, so ...second = -1-Requ'd value
5057  LocationNameMultiMap.insert(LocationNameEntry);
5058  }
5059  if(TrackElement.HLoc < HLocMin)
5060  HLocMin = TrackElement.HLoc; // exclude erase elements as HLoc & VLoc set to -2000000000
5061  if(TrackElement.HLoc > HLocMax)
5062  HLocMax = TrackElement.HLoc;
5063  if(TrackElement.VLoc < VLocMin)
5064  VLocMin = TrackElement.VLoc;
5065  if(TrackElement.VLoc > VLocMax)
5066  VLocMax = TrackElement.VLoc;
5067  }
5068  }
5069 // CheckMapAndTrack(6);//test drop these to speed up, still checked outside this function
5070 // CheckMapAndInactiveTrack(6);//test
5071 
5072 // CheckLocationNameMultiMap(14);//test Can't test here as when loading the ActiveTrackElementName elements will be out of step
5073 // with the Platforms until layout fully loaded
5074  Utilities->CallLogPop(511);
5075 }
5076 
5077 // ---------------------------------------------------------------------------
5078 
5079 int TTrack::GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5080 {
5081  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionFromTrackMap," + AnsiString(HLoc) + "," +
5082  AnsiString(VLoc));
5083  THVPair TrackMapKeyPair;
5084 
5085  FoundFlag = false;
5086  TTrackMapIterator TrackMapPtr;
5087 
5088  TrackMapKeyPair.first = HLoc;
5089  TrackMapKeyPair.second = VLoc;
5090  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5091  if(TrackMapPtr == TrackMap.end())
5092  {
5093  Utilities->CallLogPop(512);
5094  return -1; // nothing found
5095  }
5096  else
5097  {
5098  FoundFlag = true;
5099  Utilities->CallLogPop(513);
5100  return TrackMapPtr->second;
5101  }
5102 }
5103 
5104 // ---------------------------------------------------------------------------
5105 
5106 TTrackElement &TTrack::GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
5107 {
5108  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5109  AnsiString(VLoc));
5110  THVPair TrackMapKeyPair;
5111  TTrackMapIterator TrackMapPtr;
5112 
5113  TrackMapKeyPair.first = HLoc;
5114  TrackMapKeyPair.second = VLoc;
5115  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5116  if(TrackMapPtr == TrackMap.end())
5117  {
5118  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5119  throw Exception(Message);
5120  }
5121  else
5122  {
5123  Utilities->CallLogPop(1943);
5124  return TrackElementAt(871, TrackMapPtr->second);
5125  }
5126 }
5127 
5128 // ---------------------------------------------------------------------------
5129 
5131 {
5132  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetInactiveTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5133  AnsiString(VLoc));
5134  THVPair InactiveTrackMapKeyPair;
5135  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5136 
5137  InactiveTrackMapKeyPair.first = HLoc;
5138  InactiveTrackMapKeyPair.second = VLoc;
5139  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5140  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5141  {
5142  AnsiString Message = "Inactive element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5143  throw Exception(Message);
5144  }
5145  else
5146  {
5147  Utilities->CallLogPop(1949);
5148  return InactiveTrackElementAt(34, InactiveTrackMapPtr->second);
5149  }
5150 }
5151 
5152 // ---------------------------------------------------------------------------
5153 
5154 bool TTrack::TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5155 {
5156  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementPresentAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5157  bool Present = true;
5158  THVPair TrackMapKeyPair;
5159  TTrackMapIterator TrackMapPtr;
5160 
5161  TrackMapKeyPair.first = HLoc;
5162  TrackMapKeyPair.second = VLoc;
5163  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5164  if(TrackMapPtr == TrackMap.end())
5165  {
5166  Present = false;
5167  }
5168  Utilities->CallLogPop(2057);
5169  return Present;
5170 }
5171 
5172 // ---------------------------------------------------------------------------
5173 
5174 bool TTrack::InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5175 {
5176  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementPresentAtHV," + AnsiString(HLoc) + "," +
5177  AnsiString(VLoc));
5178  bool Present = true;
5179  THVPair InactiveTrackMapKeyPair;
5180  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5181 
5182  InactiveTrackMapKeyPair.first = HLoc;
5183  InactiveTrackMapKeyPair.second = VLoc;
5184  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5185  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5186  {
5187  Present = false;
5188  }
5189  Utilities->CallLogPop(2058);
5190  return Present;
5191 }
5192 
5193 // ---------------------------------------------------------------------------
5194 
5195 TTrack::TIMPair TTrack::GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5196  // max number of elements is 2, for platforms
5197  // note that both elements of RetPair may be the same, if only one present in map
5198 {
5199  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromInactiveTrackMap," + AnsiString(HLoc) + "," +
5200  AnsiString(VLoc));
5201  THVPair InactiveTrackMapKeyPair;
5202  TIMPair RetPair;
5203  TInactiveTrackRange InactiveTrackRange;
5204 
5205  FoundFlag = false;
5206  InactiveTrackMapKeyPair.first = HLoc;
5207  InactiveTrackMapKeyPair.second = VLoc;
5208  if(InactiveTrack2MultiMap.empty())
5209  {
5210  RetPair.first = 0;
5211  RetPair.second = 0;
5212  Utilities->CallLogPop(1815);
5213  return RetPair; // map empty
5214  }
5215  InactiveTrackRange = InactiveTrack2MultiMap.equal_range(InactiveTrackMapKeyPair);
5216  if(InactiveTrackRange.first == InactiveTrackRange.second)
5217  {
5218  RetPair.first = 0;
5219  RetPair.second = 0;
5220  Utilities->CallLogPop(514);
5221  return RetPair; // nothing found
5222  }
5223  else
5224  {
5225  RetPair.first = InactiveTrackRange.first->second;
5226  RetPair.second = (--InactiveTrackRange.second)->second;
5227  FoundFlag = true;
5228  Utilities->CallLogPop(515);
5229  return RetPair;
5230  }
5231 }
5232 
5233 // ---------------------------------------------------------------------------
5234 
5235 bool TTrack::MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
5236 {
5237 // only change where have adjacent points with their diverging links connected - not appropriate for non-straight points
5238  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MatchingPoint," + AnsiString(TrackVectorPosition) + "," +
5239  AnsiString(DivergingPosition));
5240  TTrackElement T1 = TrackElementAt(15, TrackVectorPosition);
5241  TTrackElement T2 = TrackElementAt(16, DivergingPosition);
5242  int SpeedTag1 = T1.SpeedTag;
5243  int SpeedTag2 = T2.SpeedTag;
5244 
5245  if(T1.Attribute != T2.Attribute)
5246  {
5247  Utilities->CallLogPop(516);
5248  return false;
5249  }
5250  if(((SpeedTag1 == 7) && (SpeedTag2 == 10)) || // straight track hor, diverging track vert
5251  ((SpeedTag1 == 10) && (SpeedTag2 == 7)) || ((SpeedTag1 == 8) && (SpeedTag2 == 9)) || ((SpeedTag1 == 9) && (SpeedTag2 == 8)) ||
5252  ((SpeedTag1 == 11) && (SpeedTag2 == 14)) || // straight track vert, diverging track hor
5253  ((SpeedTag1 == 14) && (SpeedTag2 == 11)) || ((SpeedTag1 == 12) && (SpeedTag2 == 13)) || ((SpeedTag1 == 13) && (SpeedTag2 == 12)) ||
5254  ((SpeedTag1 == 28) && (SpeedTag2 == 31)) || // straight track hor, diverging track 45 deg
5255  ((SpeedTag1 == 31) && (SpeedTag2 == 28)) || ((SpeedTag1 == 29) && (SpeedTag2 == 30)) || ((SpeedTag1 == 30) && (SpeedTag2 == 29)) ||
5256  ((SpeedTag1 == 32) && (SpeedTag2 == 35)) || // straight track vert, diverging track 45 deg
5257  ((SpeedTag1 == 35) && (SpeedTag2 == 32)) || ((SpeedTag1 == 33) && (SpeedTag2 == 34)) || ((SpeedTag1 == 34) && (SpeedTag2 == 33)) ||
5258  ((SpeedTag1 == 36) && (SpeedTag2 == 39)) || // straight track 45 deg, diverging track vert
5259  ((SpeedTag1 == 39) && (SpeedTag2 == 36)) || ((SpeedTag1 == 37) && (SpeedTag2 == 38)) || ((SpeedTag1 == 38) && (SpeedTag2 == 37)) ||
5260  ((SpeedTag1 == 40) && (SpeedTag2 == 43)) || // straight track 45 deg, diverging track hor
5261  ((SpeedTag1 == 43) && (SpeedTag2 == 40)) || ((SpeedTag1 == 41) && (SpeedTag2 == 42)) || ((SpeedTag1 == 42) && (SpeedTag2 == 41)))
5262  {
5263  Utilities->CallLogPop(517);
5264  return true;
5265  }
5266  else
5267  {
5268  Utilities->CallLogPop(518);
5269  return false;
5270  }
5271 }
5272 
5273 // ---------------------------------------------------------------------------
5274 
5275 /*
5276  bool TMapComp::operator() (const THVPair& lower, const THVPair& higher) const///HLoc VLoc
5277  {
5278  if(lower.second < higher.second) return true;
5279  else if(lower.second > higher.second) return false;
5280  else if(lower.second == higher.second)
5281  {
5282  if(lower.first < higher.first) return true;
5283  }
5284  return false;
5285  }
5286 */
5287 // ---------------------------------------------------------------------------
5288 
5289 void TTrack::PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
5290  // no need to check corresponding gap, if that not set correctly it will be picked up in GapsUnset()
5291 {
5292  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotGap," + TrackElement.LogTrack(1));
5293  if(TrackElement.TrackType != GapJump)
5294  {
5295  throw Exception("Error, Wrong track type in PlotGap");
5296  }
5297  if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] > -1))
5298  {
5299  Disp->PlotOutput(39, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88set);
5300  }
5301  else if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] == -1))
5302  {
5303  Disp->PlotOutput(40, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88unset);
5304  }
5305  if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] > -1))
5306  {
5307  Disp->PlotOutput(41, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89set);
5308  }
5309  else if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] == -1))
5310  {
5311  Disp->PlotOutput(42, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89unset);
5312  }
5313  if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] > -1))
5314  {
5315  Disp->PlotOutput(43, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90set);
5316  }
5317  else if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] == -1))
5318  {
5319  Disp->PlotOutput(44, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90unset);
5320  }
5321  if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] > -1))
5322  {
5323  Disp->PlotOutput(45, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91set);
5324  }
5325  else if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] == -1))
5326  {
5327  Disp->PlotOutput(46, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91unset);
5328  }
5329  if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] > -1))
5330  {
5331  Disp->PlotOutput(47, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92set);
5332  }
5333  else if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] == -1))
5334  {
5335  Disp->PlotOutput(48, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92unset);
5336  }
5337  if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] > -1))
5338  {
5339  Disp->PlotOutput(49, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93set);
5340  }
5341  else if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] == -1))
5342  {
5343  Disp->PlotOutput(50, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93unset);
5344  }
5345  if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] > -1))
5346  {
5347  Disp->PlotOutput(51, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94set);
5348  }
5349  else if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] == -1))
5350  {
5351  Disp->PlotOutput(52, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94unset);
5352  }
5353  if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] > -1))
5354  {
5355  Disp->PlotOutput(53, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95set);
5356  }
5357  else if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] == -1))
5358  {
5359  Disp->PlotOutput(54, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95unset);
5360  }
5361  Utilities->CallLogPop(1101);
5362 }
5363 
5364 // ---------------------------------------------------------------------------
5365 
5366 void TTrack::PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
5367 {
5368  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPoints," + TrackElement.LogTrack(2));
5369  if(TrackElement.TrackType != Points)
5370  {
5371  throw Exception("Error, Wrong track type in PlotPoints");
5372  }
5373  Disp->PlotPointBlank(0, TrackElement.HLoc, TrackElement.VLoc); // to get rid of earlier fillet
5374  TrackElement.PlotVariableTrackElement(4, Disp);
5375  if(BothFillets)
5376  {
5377  if(TrackElement.SpeedTag < 28)
5378  {
5379  Disp->PlotOutput(55, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][0]);
5380  Disp->PlotOutput(73, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][1]);
5381  }
5382  else if(TrackElement.SpeedTag < 132)
5383  {
5384  Disp->PlotOutput(56, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][0]);
5385  Disp->PlotOutput(74, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][1]);
5386  }
5387  else
5388  {
5389  Disp->PlotOutput(70, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][0]);
5390  Disp->PlotOutput(71, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][1]);
5391  }
5392  }
5393  else
5394  {
5395  if(TrackElement.SpeedTag < 28)
5396  {
5397  Disp->PlotOutput(75, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5398  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
5399  }
5400  else if(TrackElement.SpeedTag < 132)
5401  {
5402  Disp->PlotOutput(76, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5403  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
5404  }
5405  else
5406  {
5407  Disp->PlotOutput(72, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5408  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
5409  }
5410  }
5411 // replot platform if required
5412  TIMPair IMPair;
5413  bool FoundFlag;
5414 
5415  IMPair = GetVectorPositionsFromInactiveTrackMap(15, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5416  if(FoundFlag)
5417  { // only one platform possible at points so only need to plot IMPair.first
5418  TTrackElement PlatElement = InactiveTrackElementAt(89, IMPair.first);
5419  PlatElement.PlotVariableTrackElement(5, Disp); // to plot as striped or non-striped depending on whether named or not
5420  }
5421  Utilities->CallLogPop(519);
5422 }
5423 
5424 // ---------------------------------------------------------------------------
5425 
5426 void TTrack::PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
5427 {
5428 // Can't use TrackElement.PlotVariableTrackElement() here as graphic changes depending on signal colour
5429  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignal," + TrackElement.LogTrack(3));
5430  if(TrackElement.TrackType != SignalPost)
5431  {
5432  throw Exception("Error, Wrong track type in PlotSignal");
5433  }
5434  for(int x = 0; x < 40; x++)
5435  {
5436  if((SigTable[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == TrackElement.Attribute))
5437  {
5438  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
5439  Disp->PlotSignalBlank(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
5440 // in case existing signal is a double yellow
5441  // plot platforms if present
5442 // Graphics::TBitmap* SignalPlatformGraphic;
5443 // if(PlatformOnSignalSide(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, SignalPlatformGraphic))
5444 // Above dropped at v2.3.0. Now plot either or both platforms if present regardless of which side they are on. The platforms will
5445 // be consistent with the signal graphic as can't enter an inappropriate platform. The new right hand signal option caused platforms
5446 // to not be plotted with the above function.
5447  PlotSignalPlatforms(0, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
5448  // now plot signal (double yellow overwrites most of signal platform if present)
5449  // additions at version 0.6 for other aspects & ground sigs
5450  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
5451  {
5452  Disp->PlotOutput(117, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableThreeAspect[x].SigPtr);
5453  }
5454  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
5455  {
5456  Disp->PlotOutput(118, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableTwoAspect[x].SigPtr);
5457  }
5458  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
5459  {
5460  Disp->PlotOutput(119, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
5461  }
5462  else // 4 aspect
5463  {
5464  Disp->PlotOutput(58, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTable[x].SigPtr);
5465  }
5466  if((TrackElement.CallingOnSet) && (TrackElement.SigAspect != TTrackElement::GroundSignal))
5467  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
5468  {
5469  if(TrackElement.SpeedTag == 68)
5470  {
5471  Disp->PlotOutput(59, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm68CallingOn);
5472  }
5473  if(TrackElement.SpeedTag == 69)
5474  {
5475  Disp->PlotOutput(60, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm69CallingOn);
5476  }
5477  if(TrackElement.SpeedTag == 70)
5478  {
5479  Disp->PlotOutput(61, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm70CallingOn);
5480  }
5481  if(TrackElement.SpeedTag == 71)
5482  {
5483  Disp->PlotOutput(62, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm71CallingOn);
5484  }
5485  if(TrackElement.SpeedTag == 72)
5486  {
5487  Disp->PlotOutput(63, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm72CallingOn);
5488  }
5489  if(TrackElement.SpeedTag == 73)
5490  {
5491  Disp->PlotOutput(64, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm73CallingOn);
5492  }
5493  if(TrackElement.SpeedTag == 74)
5494  {
5495  Disp->PlotOutput(65, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm74CallingOn);
5496  }
5497  if(TrackElement.SpeedTag == 75)
5498  {
5499  Disp->PlotOutput(66, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm75CallingOn);
5500  }
5501  }
5502  else if((TrackElement.CallingOnSet) && (TrackElement.SigAspect == TTrackElement::GroundSignal))
5503  // ground signal calling on, need to use normal proceed aspect
5504  {
5505  for(int x = 0; x < 40; x++)
5506  {
5507  if((SigTableGroundSignal[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
5508  {
5509  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
5510  Disp->PlotSignalBlank(1, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
5511  // plot special signal platform if present
5512  Graphics::TBitmap* SignalPlatformGraphic;
5513  PlotSignalPlatforms(1, TrackElement.HLoc, TrackElement.VLoc, Disp);
5514  // now plot signal
5515  Disp->PlotOutput(123, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
5516  }
5517  }
5518  }
5519  break;
5520  }
5521  }
5522  Utilities->CallLogPop(520);
5523 }
5524 
5525 // ---------------------------------------------------------------------------
5526 
5527 void TTrack::PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
5528 {
5529  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignalPlatforms," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5530  bool FoundFlag;
5531  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(13, HLoc, VLoc, FoundFlag);
5532 
5533  if(!FoundFlag)
5534  {
5535  Utilities->CallLogPop(2112);
5536  return;
5537  }
5538  TTrackElement IAElement1 = InactiveTrackElementAt(124, IMPair.first);
5539  TTrackElement IAElement2 = InactiveTrackElementAt(125, IMPair.second);
5540 
5541  // don't want 'else if' for the below as may need to plot 2 platforms
5542  if((IAElement1.SpeedTag == 76) || (IAElement2.SpeedTag == 76)) // top plat
5543  {
5544  if(IAElement1.LocationName == "") // '2' will be same
5545  {
5546  Disp->PlotOutput(239, HLoc * 16, VLoc * 16, RailGraphics->gl76Striped);
5547  }
5548  else
5549  {
5550  Disp->PlotOutput(240, HLoc * 16, VLoc * 16, RailGraphics->gl76);
5551  }
5552  }
5553  if((IAElement1.SpeedTag == 77) || (IAElement2.SpeedTag == 77)) // bot plat
5554  {
5555  if(IAElement1.LocationName == "") // '2' will be same
5556  {
5557  Disp->PlotOutput(241, HLoc * 16, VLoc * 16, RailGraphics->bm77Striped);
5558  }
5559  else
5560  {
5561  Disp->PlotOutput(242, HLoc * 16, VLoc * 16, RailGraphics->bm77);
5562  }
5563  }
5564  if((IAElement1.SpeedTag == 78) || (IAElement2.SpeedTag == 78)) // lh plat
5565  {
5566  if(IAElement1.LocationName == "") // '2' will be same
5567  {
5568  Disp->PlotOutput(243, HLoc * 16, VLoc * 16, RailGraphics->bm78Striped);
5569  }
5570  else
5571  {
5572  Disp->PlotOutput(244, HLoc * 16, VLoc * 16, RailGraphics->bm78);
5573  }
5574  }
5575  if((IAElement1.SpeedTag == 79) || (IAElement2.SpeedTag == 79)) // rh plat
5576  {
5577  if(IAElement1.LocationName == "") // '2' will be same
5578  {
5579  Disp->PlotOutput(245, HLoc * 16, VLoc * 16, RailGraphics->gl79Striped);
5580  }
5581  else
5582  {
5583  Disp->PlotOutput(246, HLoc * 16, VLoc * 16, RailGraphics->gl79);
5584  }
5585  }
5586  Utilities->CallLogPop(2113);
5587 }
5588 
5589 // ---------------------------------------------------------------------------
5590 
5591 void TTrack::SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
5592 {
5593 // Set attrs to 0=closed to trains; 1=open to trains; 2 = changing = closed to trains
5594  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LowerLinkedLevelCrossingBarrierAttributes," + AnsiString(HLoc) + "," +
5595  AnsiString(VLoc));
5596 // find topmost LC, opening them all (to trains) in turn
5597  int UpStep = 0;
5598 
5599  while(IsLCAtHV(0, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
5600  {
5601  SetLCAttributeAtHV(0, HLoc, (VLoc + UpStep), Attr);
5602  UpStep--;
5603  }
5604 // now find bottommost LC, opening them all (to trains) in turn
5605  int DownStep = 1;
5606 
5607  while(IsLCAtHV(1, HLoc, (VLoc + DownStep)))
5608  {
5609  SetLCAttributeAtHV(1, HLoc, (VLoc + DownStep), Attr);
5610  DownStep++;
5611  }
5612 // find leftmost LC, opening them all (to trains) in turn
5613  int LeftStep = 0;
5614 
5615  while(IsLCAtHV(2, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
5616  {
5617  SetLCAttributeAtHV(2, (HLoc + LeftStep), VLoc, Attr);
5618  LeftStep--;
5619  }
5620 // now find rightmost LC, opening them all (to trains) in turn
5621  int RightStep = 1;
5622 
5623  while(IsLCAtHV(3, (HLoc + RightStep), VLoc))
5624  {
5625  SetLCAttributeAtHV(3, (HLoc + RightStep), VLoc, Attr);
5626  RightStep++;
5627  }
5628  Utilities->CallLogPop(1915);
5629 }
5630 
5631 // ---------------------------------------------------------------------------
5632 
5633 void TTrack::SetLinkedManualLCs(int Caller, int HLoc, int VLoc) //sets ConsecSignals to 2 for all linked LCs
5634 {
5635  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLinkedManualLCs," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5636 // work upwards setting all to manual
5637  int UpStep = -1;
5638 
5639  while(IsLCAtHV(51, HLoc, (VLoc + UpStep)))
5640  {
5641  SetBarriersDownLCToManual(0, HLoc, (VLoc + UpStep));
5642  UpStep--;
5643  }
5644 // work downwards setting all to manual
5645  int DownStep = 1;
5646 
5647  while(IsLCAtHV(52, HLoc, (VLoc + DownStep)))
5648  {
5649  SetBarriersDownLCToManual(1, HLoc, (VLoc + DownStep));
5650  DownStep++;
5651  }
5652 // work leftwards setting all to manual
5653  int LeftStep = -1;
5654 
5655  while(IsLCAtHV(53, (HLoc + LeftStep), VLoc))
5656  {
5657  SetBarriersDownLCToManual(2, (HLoc + LeftStep), VLoc);
5658  LeftStep--;
5659  }
5660 // work rightwards setting all to manual
5661  int RightStep = 1;
5662 
5663  while(IsLCAtHV(54, (HLoc + RightStep), VLoc))
5664  {
5665  SetBarriersDownLCToManual(3, (HLoc + RightStep), VLoc);
5666  RightStep++;
5667  }
5668  Utilities->CallLogPop(2242);
5669 }
5670 
5671 // ---------------------------------------------------------------------------
5672 
5673 void TTrack::SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
5674 {// Set ConsecSignals value to 2 to indicate barriers manually closed
5675  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetBarriersDownLCToManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5676  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
5677  {
5678  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc))
5679  {
5680  BarriersDownVector.at(x).ConsecSignals = 2;
5681  break;
5682  }
5683  }
5684  Utilities->CallLogPop(2243);
5685 }
5686 
5687 // ---------------------------------------------------------------------------
5688 
5689 bool TTrack::AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
5690 {
5691  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedBarrierDownVectorManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5692 // work upwards
5693  int UpStep = 0; //start with this location
5694 
5695  while(IsLCAtHV(55, HLoc, (VLoc + UpStep)))
5696  {
5697  if(IsBarrierDownVectorAtHVManual(0, HLoc, (VLoc + UpStep), BDVectorPos))
5698  {
5699  Utilities->CallLogPop(2244);
5700  return true;
5701  }
5702  UpStep--;
5703  }
5704 // work downwards
5705  int DownStep = 1;
5706 
5707  while(IsLCAtHV(56, HLoc, (VLoc + DownStep)))
5708  {
5709  if(IsBarrierDownVectorAtHVManual(1, HLoc, (VLoc + DownStep), BDVectorPos))
5710  {
5711  Utilities->CallLogPop(2245);
5712  return true;
5713  }
5714  DownStep++;
5715  }
5716 // work leftwards
5717  int LeftStep = -1;
5718 
5719  while(IsLCAtHV(57, (HLoc + LeftStep), VLoc))
5720  {
5721  if(IsBarrierDownVectorAtHVManual(2, (HLoc + LeftStep), VLoc, BDVectorPos))
5722  {
5723  Utilities->CallLogPop(2246);
5724  return true;
5725  }
5726  LeftStep--;
5727  }
5728 // work rightwards
5729  int RightStep = 1;
5730 
5731  while(IsLCAtHV(58, (HLoc + RightStep), VLoc))
5732  {
5733  if(IsBarrierDownVectorAtHVManual(3, (HLoc + RightStep), VLoc, BDVectorPos))
5734  {
5735  Utilities->CallLogPop(2247);
5736  return true;
5737  }
5738  RightStep++;
5739  }
5740  Utilities->CallLogPop(2248);
5741  return false;
5742 }
5743 
5744 // ---------------------------------------------------------------------------
5745 
5746 bool TTrack::IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
5747 {
5748  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierDownVectorAtHVManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5749  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
5750  {
5751  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc) && (BarriersDownVector.at(x).ConsecSignals == 2))
5752  {
5753  BDVectorPos = x;
5754  Utilities->CallLogPop(2249);
5755  return true;
5756  }
5757  }
5758  BDVectorPos = -1;
5759  Utilities->CallLogPop(2250);
5760  return false;
5761 }
5762 
5763 // ---------------------------------------------------------------------------
5764 
5765 void TTrack::PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int ConsecSignals, TDisplay *Disp, bool Manual)
5766  // open to trains
5767  // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
5768 {
5769  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotLoweredLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
5770  AnsiString(VLoc));
5771  if(!IsLCAtHV(4, HLoc, VLoc))
5772  {
5773  throw Exception("Error, Wrong track type in PlotAndLowerLevelCrossingBarriers");
5774  }
5775  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
5776  {
5777  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndLowerLevelCrossingBarriers");
5778  }
5779 // check for adjacent LCs & if so open (to trains)
5780  if(BaseElementSpeedTag == 1) // hor track element
5781  {
5782  // find topmost LC, opening them all (to trains) in turn
5783  int UpStep = 0;
5784  while(IsLCAtHV(5, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
5785  {
5786  UpStep--;
5787  }
5788  UpStep++;
5789  // now find bottommost LC, opening them all (to trains) in turn
5790  int DownStep = 1;
5791  while(IsLCAtHV(6, HLoc, (VLoc + DownStep)))
5792  {
5793  DownStep++;
5794  }
5795  DownStep--;
5796  // now plot graphics, UpStep is smallest & DownStep largest
5797  // RouteGraphic is the coloured track element, BaseGraphic is non-coloured
5798  // Only need to plot the coloured graphic for the HLoc & VLoc in the vector as that is the route that is causeing the LC to flash
5799  Graphics::TBitmap *RouteGraphic;
5800  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
5801  if(ConsecSignals == 1)
5802  {
5803  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
5804  }
5805  else if(ConsecSignals == 0)
5806  {
5807  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
5808  }
5809  else //manual - no route
5810  {
5811  RouteGraphic = BaseGraphic;
5812  }
5813 // LinkSigRouteGraphicsPtr[0] hor } pref dir
5814 // LinkSigRouteGraphicsPtr[1] ver }
5815 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
5816 // LinkNonSigRouteGraphicsPtr[1] ver }
5817 
5818  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
5819  {
5820  Disp->PlotOutput(132, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5821  Disp->PlotOutput(133, HLoc * 16, VLoc * 16, RouteGraphic);
5822  if(!Manual)
5823  {
5824  Disp->PlotOutput(134, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
5825  }
5826  else
5827  {
5828  Disp->PlotOutput(247, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
5829  }
5830  }
5831  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
5832  {
5833  if(UpStep == 0)
5834  {
5835  Disp->PlotOutput(135, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
5836  Disp->PlotOutput(136, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
5837  if(!Manual)
5838  {
5839  Disp->PlotOutput(137, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5840  }
5841  else
5842  {
5843  Disp->PlotOutput(248, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
5844  }
5845  Disp->PlotOutput(138, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
5846  Disp->PlotOutput(139, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
5847  if(!Manual)
5848  {
5849  Disp->PlotOutput(140, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5850  }
5851  else
5852  {
5853  Disp->PlotOutput(249, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
5854  }
5855  }
5856  else
5857  {
5858  Disp->PlotOutput(195, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
5859  Disp->PlotOutput(196, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
5860  if(!Manual)
5861  {
5862  Disp->PlotOutput(197, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5863  }
5864  else
5865  {
5866  Disp->PlotOutput(250, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
5867  }
5868  Disp->PlotOutput(198, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
5869  Disp->PlotOutput(199, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
5870  if(!Manual)
5871  {
5872  Disp->PlotOutput(200, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5873  }
5874  else
5875  {
5876  Disp->PlotOutput(251, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
5877  }
5878  }
5879  }
5880  else // at least one plain graphic
5881  {
5882  if(UpStep == 0)
5883  {
5884  Disp->PlotOutput(141, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
5885  Disp->PlotOutput(142, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
5886  if(!Manual)
5887  {
5888  Disp->PlotOutput(143, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5889  }
5890  else
5891  {
5892  Disp->PlotOutput(252, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
5893  }
5894  Disp->PlotOutput(144, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
5895  Disp->PlotOutput(145, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
5896  if(!Manual)
5897  {
5898  Disp->PlotOutput(146, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5899  }
5900  else
5901  {
5902  Disp->PlotOutput(253, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
5903  }
5904  }
5905  else if(DownStep == 0)
5906  {
5907  Disp->PlotOutput(201, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
5908  Disp->PlotOutput(202, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
5909  if(!Manual)
5910  {
5911  Disp->PlotOutput(203, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5912  }
5913  else
5914  {
5915  Disp->PlotOutput(254, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
5916  }
5917  Disp->PlotOutput(204, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
5918  Disp->PlotOutput(205, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
5919  if(!Manual)
5920  {
5921  Disp->PlotOutput(206, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5922  }
5923  else
5924  {
5925  Disp->PlotOutput(255, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
5926  }
5927  }
5928  else
5929  {
5930  Disp->PlotOutput(207, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
5931  Disp->PlotOutput(208, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
5932  if(!Manual)
5933  {
5934  Disp->PlotOutput(209, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5935  }
5936  else
5937  {
5938  Disp->PlotOutput(256, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
5939  }
5940  Disp->PlotOutput(210, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
5941  Disp->PlotOutput(211, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
5942  if(!Manual)
5943  {
5944  Disp->PlotOutput(212, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5945  }
5946  else
5947  {
5948  Disp->PlotOutput(257, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
5949  }
5950  }
5951  for(int x = (UpStep + 1); x < DownStep; x++)
5952  {
5953  Disp->PlotOutput(147, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
5954  if(x == 0)
5955  Disp->PlotOutput(148, HLoc * 16, (VLoc + x) * 16, RouteGraphic);
5956  else
5957  Disp->PlotOutput(213, HLoc * 16, (VLoc + x) * 16, BaseGraphic);
5958  if(!Manual)
5959  {
5960  Disp->PlotOutput(149, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
5961  }
5962  else
5963  {
5964  Disp->PlotOutput(258, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
5965  }
5966  }
5967  }
5968  Disp->Update();
5969  Utilities->CallLogPop(1958);
5970  return;
5971  }
5972 
5973  else // ver track element
5974  {
5975  // find leftmost LC, opening them all (to trains) in turn
5976  int LStep = 0;
5977  while(IsLCAtHV(7, (HLoc + LStep), VLoc))
5978  {
5979  LStep--;
5980  }
5981  LStep++;
5982  // now find rightmost LC, opening them all (to trains) in turn
5983  int RStep = 1;
5984  while(IsLCAtHV(8, (HLoc + RStep), VLoc))
5985  {
5986  RStep++;
5987  }
5988  RStep--;
5989  // now plot graphics, LStep is smallest & RStep largest
5990  Graphics::TBitmap *RouteGraphic;
5991  Graphics::TBitmap *BaseGraphic = RailGraphics->gl2;
5992  if(ConsecSignals == 1)
5993  {
5994  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
5995  }
5996  else if(ConsecSignals == 0)
5997  {
5998  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
5999  }
6000  else //manual
6001  {
6002  RouteGraphic = BaseGraphic;
6003  }
6004 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6005 // LinkSigRouteGraphicsPtr[1] ver }
6006 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6007 // LinkNonSigRouteGraphicsPtr[1] ver }
6008  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6009  {
6010  Disp->PlotOutput(150, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6011  Disp->PlotOutput(151, HLoc * 16, VLoc * 16, RouteGraphic);
6012  if(!Manual)
6013  {
6014  Disp->PlotOutput(152, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6015  }
6016  else
6017  {
6018  Disp->PlotOutput(259, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6019  }
6020  }
6021  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6022  {
6023  if(LStep == 0)
6024  {
6025  Disp->PlotOutput(153, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6026  Disp->PlotOutput(154, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6027  if(!Manual)
6028  {
6029  Disp->PlotOutput(155, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6030  }
6031  else
6032  {
6033  Disp->PlotOutput(260, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6034  }
6035  Disp->PlotOutput(156, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6036  Disp->PlotOutput(157, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6037  if(!Manual)
6038  {
6039  Disp->PlotOutput(158, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6040  }
6041  else
6042  {
6043  Disp->PlotOutput(261, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6044  }
6045  }
6046  else
6047  {
6048  Disp->PlotOutput(214, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6049  Disp->PlotOutput(215, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6050  if(!Manual)
6051  {
6052  Disp->PlotOutput(216, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6053  }
6054  else
6055  {
6056  Disp->PlotOutput(262, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6057  }
6058  Disp->PlotOutput(217, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6059  Disp->PlotOutput(218, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6060  if(!Manual)
6061  {
6062  Disp->PlotOutput(219, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6063  }
6064  else
6065  {
6066  Disp->PlotOutput(263, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6067  }
6068  }
6069  }
6070  else // at least one plain graphic
6071  {
6072  if(LStep == 0)
6073  {
6074  Disp->PlotOutput(159, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6075  Disp->PlotOutput(160, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6076  if(!Manual)
6077  {
6078  Disp->PlotOutput(161, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6079  }
6080  else
6081  {
6082  Disp->PlotOutput(264, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6083  }
6084  Disp->PlotOutput(162, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6085  Disp->PlotOutput(163, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6086  if(!Manual)
6087  {
6088  Disp->PlotOutput(164, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6089  }
6090  else
6091  {
6092  Disp->PlotOutput(265, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6093  }
6094  }
6095  else if(RStep == 0)
6096  {
6097  Disp->PlotOutput(220, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6098  Disp->PlotOutput(221, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6099  if(!Manual)
6100  {
6101  Disp->PlotOutput(222, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6102  }
6103  else
6104  {
6105  Disp->PlotOutput(266, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6106  }
6107  Disp->PlotOutput(223, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6108  Disp->PlotOutput(224, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6109  if(!Manual)
6110  {
6111  Disp->PlotOutput(225, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6112  }
6113  else
6114  {
6115  Disp->PlotOutput(267, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6116  }
6117  }
6118  else
6119  {
6120  Disp->PlotOutput(226, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6121  Disp->PlotOutput(227, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6122  if(!Manual)
6123  {
6124  Disp->PlotOutput(228, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6125  }
6126  else
6127  {
6128  Disp->PlotOutput(268, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6129  }
6130  Disp->PlotOutput(229, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6131  Disp->PlotOutput(230, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6132  if(!Manual)
6133  {
6134  Disp->PlotOutput(231, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6135  }
6136  else
6137  {
6138  Disp->PlotOutput(269, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6139  }
6140  }
6141  for(int x = (LStep + 1); x < RStep; x++)
6142  {
6143  Disp->PlotOutput(165, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6144  if(x == 0)
6145  {
6146  Disp->PlotOutput(166, (HLoc + x) * 16, VLoc * 16, RouteGraphic);
6147  }
6148  else
6149  {
6150  Disp->PlotOutput(232, (HLoc + x) * 16, VLoc * 16, BaseGraphic);
6151  }
6152  if(!Manual)
6153  {
6154  Disp->PlotOutput(167, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
6155  }
6156  else
6157  {
6158  Disp->PlotOutput(270, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
6159  }
6160  }
6161  }
6162  Disp->Update();
6163  Utilities->CallLogPop(1896);
6164  return;
6165  }
6166 }
6167 
6168 // ---------------------------------------------------------------------------
6169 
6170 void TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual) // open to trains
6171  // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6172 {
6173  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers," +
6174  AnsiString(HLoc) + "," + AnsiString(VLoc));
6175  if(!IsLCAtHV(29, HLoc, VLoc))
6176  {
6177  throw Exception("Error, Wrong track type in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
6178  }
6179  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6180  {
6181  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
6182  }
6183 // check for adjacent LCs & if so open (to trains)
6184  if(BaseElementSpeedTag == 1) // hor track element
6185  {
6186  // find topmost LC, opening them all (to trains) in turn
6187  int UpStep = 0;
6188  while(IsLCAtHV(30, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6189  {
6190  UpStep--;
6191  }
6192  UpStep++;
6193  // now find bottommost LC, opening them all (to trains) in turn
6194  int DownStep = 1;
6195  while(IsLCAtHV(31, HLoc, (VLoc + DownStep)))
6196  {
6197  DownStep++;
6198  }
6199  DownStep--;
6200  // now plot graphics, UpStep is smallest & DownStep largest
6201  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6202  {
6203  if(!Manual)
6204  {
6205  Disp->PlotOutput(179, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6206  }
6207  else
6208  {
6209  Disp->PlotOutput(271, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6210  }
6211  }
6212  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6213  {
6214  if(!Manual)
6215  {
6216  Disp->PlotOutput(180, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6217  Disp->PlotOutput(181, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6218  }
6219  else
6220  {
6221  Disp->PlotOutput(272, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6222  Disp->PlotOutput(273, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6223  }
6224  }
6225  else // at least one plain graphic
6226  {
6227  if(!Manual)
6228  {
6229  Disp->PlotOutput(182, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6230  Disp->PlotOutput(183, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6231  for(int x = (UpStep + 1); x < DownStep; x++)
6232  {
6233  Disp->PlotOutput(184, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6234  }
6235  }
6236  else
6237  {
6238  Disp->PlotOutput(274, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6239  Disp->PlotOutput(275, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6240  for(int x = (UpStep + 1); x < DownStep; x++)
6241  {
6242  Disp->PlotOutput(276, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6243  }
6244  }
6245  }
6246  // set markers
6247  for(int x = UpStep; x <= DownStep; x++)
6248  {
6249  GetInactiveTrackElementFromTrackMap(3, HLoc, (VLoc + x)).LCPlotted = true; // plotted
6250  }
6251  Display->Update();
6252  Utilities->CallLogPop(1944);
6253  return;
6254  }
6255 
6256  else // ver track element
6257  {
6258  // find leftmost LC, opening them all (to trains) in turn
6259  int LStep = 0;
6260  while(IsLCAtHV(32, (HLoc + LStep), VLoc))
6261  {
6262  LStep--;
6263  }
6264  LStep++;
6265  // now find rightmost LC, opening them all (to trains) in turn
6266  int RStep = 1;
6267  while(IsLCAtHV(33, (HLoc + RStep), VLoc))
6268  {
6269  RStep++;
6270  }
6271  RStep--;
6272  // now plot graphics, LStep is smallest & RStep largest
6273  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6274  {
6275  if(!Manual)
6276  {
6277  Disp->PlotOutput(185, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6278  }
6279  else
6280  {
6281  Disp->PlotOutput(277, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6282  }
6283  }
6284  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6285  {
6286  if(!Manual)
6287  {
6288  Disp->PlotOutput(186, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6289  Disp->PlotOutput(187, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6290  }
6291  else
6292  {
6293  Disp->PlotOutput(278, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6294  Disp->PlotOutput(279, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6295  }
6296  }
6297  else // at least one plain graphic
6298  {
6299  if(!Manual)
6300  {
6301  Disp->PlotOutput(188, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6302  Disp->PlotOutput(189, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6303  for(int x = (LStep + 1); x < RStep; x++)
6304  {
6305  Disp->PlotOutput(190, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
6306  }
6307  }
6308  else
6309  {
6310  Disp->PlotOutput(280, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6311  Disp->PlotOutput(281, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6312  for(int x = (LStep + 1); x < RStep; x++)
6313  {
6314  Disp->PlotOutput(282, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
6315  }
6316  }
6317  }
6318  // set markers
6319  for(int x = LStep; x <= RStep; x++)
6320  {
6321  GetInactiveTrackElementFromTrackMap(4, (HLoc + x), VLoc).LCPlotted = true; // plotted
6322  }
6323  Disp->Update();
6324  Utilities->CallLogPop(1945);
6325  return;
6326  }
6327 }
6328 
6329 // ---------------------------------------------------------------------------
6330 
6331 void TTrack::PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp) // closed to trains
6332  // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6333 {
6334  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotRaisedLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6335  AnsiString(VLoc));
6336  if(!IsLCAtHV(9, HLoc, VLoc))
6337  {
6338  throw Exception("Error, Wrong track type in PlotAndRaiseLevelCrossingBarriers");
6339  }
6340  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6341  {
6342  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndRaiseLevelCrossingBarriers");
6343  }
6344 // check for adjacent LCs & if so close (to trains)
6345  if(BaseElementSpeedTag == 1) // hor track element
6346  {
6347  // find topmost LC, closing them all (to trains) in turn
6348  int UpStep = 0;
6349  while(IsLCAtHV(10, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6350  {
6351  UpStep--;
6352  }
6353  UpStep++;
6354  // now find bottommost LC, opening them all (to trains) in turn
6355  int DownStep = 1;
6356  while(IsLCAtHV(11, HLoc, (VLoc + DownStep)))
6357  {
6358  DownStep++;
6359  }
6360  DownStep--;
6361  // now plot graphics, UpStep is smallest & DownStep largest
6362  for(int x = UpStep; x < (DownStep + 1); x++)
6363  {
6364  Disp->PlotOutput(168, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
6365  Disp->PlotOutput(169, HLoc * 16, (VLoc + x) * 16, RailGraphics->gl1);
6366  Disp->PlotOutput(170, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
6367  }
6368  Disp->Update();
6369  Utilities->CallLogPop(1959);
6370  return;
6371  }
6372 
6373  else // ver track element
6374  {
6375  // find leftmost LC, closing them all (to trains) in turn
6376  int LStep = 0;
6377  while(IsLCAtHV(12, (HLoc + LStep), VLoc))
6378  {
6379  LStep--;
6380  }
6381  LStep++;
6382  // now find rightmost LC, opening them all (to trains) in turn
6383  int RStep = 1;
6384  while(IsLCAtHV(13, (HLoc + RStep), VLoc))
6385  {
6386  RStep++;
6387  }
6388  RStep--;
6389  // now plot graphics, LStep is smallest & RStep largest
6390  for(int x = LStep; x < (RStep + 1); x++)
6391  {
6392  Disp->PlotOutput(171, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6393  Disp->PlotOutput(172, (HLoc + x) * 16, VLoc * 16, RailGraphics->gl2);
6394  Disp->PlotOutput(173, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
6395  }
6396  Disp->Update();
6397  Utilities->CallLogPop(1960);
6398  return;
6399  }
6400 }
6401 
6402 // ---------------------------------------------------------------------------
6403 
6404 void TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
6405  // closed to trains
6406  // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6407 {
6408  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers," +
6409  AnsiString(HLoc) + "," + AnsiString(VLoc));
6410  if(!IsLCAtHV(34, HLoc, VLoc))
6411  {
6412  throw Exception("Error, Wrong track type in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
6413  }
6414  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6415  {
6416  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
6417  }
6418  TTrackElement TE;
6419 
6420 // check for adjacent LCs & if so close (to trains)
6421  if(BaseElementSpeedTag == 1) // hor track element
6422  {
6423  // find topmost LC, closing them all (to trains) in turn
6424  int UpStep = 0;
6425  while(IsLCAtHV(35, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6426  {
6427  UpStep--;
6428  }
6429  UpStep++;
6430  // now find bottommost LC, opening them all (to trains) in turn
6431  int DownStep = 1;
6432  while(IsLCAtHV(36, HLoc, (VLoc + DownStep)))
6433  {
6434  DownStep++;
6435  }
6436  DownStep--;
6437  // now plot graphics, UpStep is smallest & DownStep largest
6438  for(int x = UpStep; x <= DownStep; x++)
6439  {
6440  Disp->PlotOutput(191, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
6441  GetInactiveTrackElementFromTrackMap(1, HLoc, (VLoc + x)).LCPlotted = true; // plotted
6442  }
6443  Display->Update();
6444  Utilities->CallLogPop(1946);
6445  return;
6446  }
6447 
6448  else // ver track element
6449  {
6450  // find leftmost LC, closing them all (to trains) in turn
6451  int LStep = 0;
6452  while(IsLCAtHV(37, (HLoc + LStep), VLoc))
6453  {
6454  LStep--;
6455  }
6456  LStep++;
6457  // now find rightmost LC, opening them all (to trains) in turn
6458  int RStep = 1;
6459  while(IsLCAtHV(38, (HLoc + RStep), VLoc))
6460  {
6461  RStep++;
6462  }
6463  RStep--;
6464  // now plot graphics, LStep is smallest & RStep largest
6465  for(int x = LStep; x <= RStep; x++)
6466  {
6467  Disp->PlotOutput(192, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
6468  GetInactiveTrackElementFromTrackMap(2, (HLoc + x), VLoc).LCPlotted = true; // plotted
6469  }
6470  Display->Update();
6471  Utilities->CallLogPop(1947);
6472  return;
6473  }
6474 }
6475 
6476 // ---------------------------------------------------------------------------
6477 
6478 void TTrack::PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int ConsecSignals, TDisplay *Disp)
6479 {
6480  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotBaseElementsOnly," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6481  Graphics::TBitmap *RouteGraphic;
6482  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
6483 
6484  if(BaseElementSpeedTag == 1)
6485  {
6486  if(ConsecSignals == 1)
6487  {
6488  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
6489  }
6490  else if(ConsecSignals == 0)
6491  {
6492  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
6493  }
6494  else //manual
6495  {
6496  RouteGraphic = BaseGraphic;
6497  }
6498 
6499  if(State == Raising)
6500  RouteGraphic = BaseGraphic;
6501  }
6502  else
6503  {
6504  BaseGraphic = RailGraphics->gl2;
6505  if(ConsecSignals == 1)
6506  {
6507  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
6508  }
6509  else if(ConsecSignals == 0)
6510  {
6511  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
6512  }
6513  else
6514  {
6515  RouteGraphic = BaseGraphic; //manual
6516  }
6517  if(State == Raising)
6518  RouteGraphic = BaseGraphic;
6519  }
6520  int UpStep = 0;
6521 
6522  while(IsLCAtHV(14, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6523  {
6524  Disp->PlotOutput(174, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6525  if(UpStep == 0)
6526  Disp->PlotOutput(175, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6527  else
6528  Disp->PlotOutput(234, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6529  UpStep--;
6530  }
6531 // now find bottommost LC, opening them all (to trains) in turn
6532  int DownStep = 1;
6533 
6534  while(IsLCAtHV(15, HLoc, (VLoc + DownStep)))
6535  {
6536  Disp->PlotOutput(176, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6537  Disp->PlotOutput(177, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6538  DownStep++;
6539  }
6540  int LeftStep = 0;
6541 
6542  while(IsLCAtHV(16, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6543  {
6544  Disp->PlotOutput(233, (HLoc + LeftStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6545  if(LeftStep == 0)
6546  Disp->PlotOutput(235, (HLoc + LeftStep) * 16, VLoc * 16, RouteGraphic);
6547  else
6548  Disp->PlotOutput(236, (HLoc + LeftStep) * 16, VLoc * 16, BaseGraphic);
6549  LeftStep--;
6550  }
6551 // now find rightmost LC, opening them all (to trains) in turn
6552  int RightStep = 1;
6553 
6554  while(IsLCAtHV(17, (HLoc + RightStep), VLoc))
6555  {
6556  Disp->PlotOutput(237, (HLoc + RightStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6557  Disp->PlotOutput(238, (HLoc + RightStep) * 16, VLoc * 16, BaseGraphic);
6558  RightStep++;
6559  }
6560  Disp->Update();
6561  Utilities->CallLogPop(1914);
6562 }
6563 
6564 // ---------------------------------------------------------------------------
6565 
6566 bool TTrack::IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully down
6567 {
6568 // return false for no LC there, flashing or a closed (to trains) LC
6569  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCBarrierDownAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6570  bool FoundFlag;
6571  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(21, HLoc, VLoc, FoundFlag);
6572 
6573  if(!FoundFlag)
6574  {
6575  Utilities->CallLogPop(1898);
6576  return false;
6577  }
6578  if(InactiveTrackElementAt(100, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
6579  {
6580  Utilities->CallLogPop(1899);
6581  return false;
6582  }
6583  if(InactiveTrackElementAt(103, IMPair.first).Attribute == 1)
6584  {
6585  Utilities->CallLogPop(1900);
6586  return true;
6587  }
6588  Utilities->CallLogPop(1901);
6589  return false;
6590 }
6591 
6592 // ---------------------------------------------------------------------------
6593 
6594 bool TTrack::IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully up
6595 {
6596 // return false for no LC there, flashing LC or open (to trains) LC
6597  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierUpLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6598  bool FoundFlag;
6599  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(24, HLoc, VLoc, FoundFlag);
6600 
6601  if(!FoundFlag)
6602  {
6603  Utilities->CallLogPop(1922);
6604  return false;
6605  }
6606  if(InactiveTrackElementAt(110, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
6607  {
6608  Utilities->CallLogPop(1923);
6609  return false;
6610  }
6611  if(InactiveTrackElementAt(111, IMPair.first).Attribute == 0)
6612  {
6613  Utilities->CallLogPop(1924);
6614  return true;
6615  }
6616  Utilities->CallLogPop(1925);
6617  return false;
6618 }
6619 
6620 // ---------------------------------------------------------------------------
6621 
6622 bool TTrack::IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
6623 {
6624 // return true for barrier in process of moving
6625  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierFlashingAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6626  bool FoundFlag;
6627  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(25, HLoc, VLoc, FoundFlag);
6628 
6629  if(!FoundFlag)
6630  {
6631  Utilities->CallLogPop(1918);
6632  return false;
6633  }
6634  if(InactiveTrackElementAt(112, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
6635  {
6636  Utilities->CallLogPop(1919);
6637  return false;
6638  }
6639  if(InactiveTrackElementAt(113, IMPair.first).Attribute == 2)
6640  {
6641  Utilities->CallLogPop(1920);
6642  return true;
6643  }
6644  Utilities->CallLogPop(1921);
6645  return false;
6646 }
6647 
6648 // ---------------------------------------------------------------------------
6649 
6650 bool TTrack::IsLCAtHV(int Caller, int HLoc, int VLoc)
6651 {
6652 // return true for an LC at H&V
6653  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6654  bool FoundFlag;
6655  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(22, HLoc, VLoc, FoundFlag);
6656 
6657  if(!FoundFlag)
6658  {
6659  Utilities->CallLogPop(1902);
6660  return false;
6661  }
6662  if(InactiveTrackElementAt(101, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
6663  {
6664  Utilities->CallLogPop(1903);
6665  return false;
6666  }
6667  Utilities->CallLogPop(1904);
6668  return true;
6669 }
6670 
6671 // ---------------------------------------------------------------------------
6672 
6673 void TTrack::SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
6674 {
6675  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCAttributeAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
6676  AnsiString(Attr));
6677  bool FoundFlag;
6678  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(23, HLoc, VLoc, FoundFlag);
6679 
6680  if(!FoundFlag)
6681  {
6682  throw Exception("Element not found in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
6683  }
6684  if(InactiveTrackElementAt(102, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
6685  {
6686  throw Exception("Element not a level crossing in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
6687  }
6688  InactiveTrackElementAt(104, IMPair.first).Attribute = Attr;
6689  Utilities->CallLogPop(1905);
6690  return;
6691 }
6692 
6693 // ---------------------------------------------------------------------------
6694 
6696 {
6697  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetLevelCrossings");
6698  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
6699  {
6700  TTrackElement InactiveTrackElement = InactiveTrackVector.at(x);
6701  if(InactiveTrackElement.TrackType == LevelCrossing)
6702  {
6703  InactiveTrackVector.at(x).Attribute = 0;
6704  // though this only resets the attributes the LC will display correctly when call Clearand.. in BaseMode
6705  }
6706  }
6707  Utilities->CallLogPop(1913);
6708  return;
6709 }
6710 
6711 // ---------------------------------------------------------------------------
6712 
6713 bool TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, bool &TrainPresent)
6714 {
6715 // return true if there is either a route set on any element or a train on any element
6716  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedLevelCrossingElementsWithRoutesOrTrains," + AnsiString(HLoc) +
6717  "," + AnsiString(VLoc));
6718 
6719  THVPair TrackMapKeyPair;
6720  TTrack::TTrackMapIterator TrackMapPtr;
6721  int DummyRouteNumber;
6722 
6723  TrainPresent = false;
6724 // find topmost LC, checking each for routes & trains
6725  int UpStep = 0;
6726 
6727  while(IsLCAtHV(25, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6728  {
6729  TrackMapKeyPair.first = HLoc;
6730  TrackMapKeyPair.second = VLoc + UpStep;
6731  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
6732  if(AllRoutes->GetRouteTypeAndNumber(20, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
6733  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
6734  {
6735  Utilities->CallLogPop(1932);
6736  return true;
6737  }
6738  if(TrackElementAt(867, TrackMapPtr->second).TrainIDOnElement != -1)
6739  {
6740  TrainPresent = true;
6741  Utilities->CallLogPop(1933);
6742  return true;
6743  }
6744  UpStep--;
6745  }
6746 // now find bottommost LC, opening them all (to trains) in turn
6747  int DownStep = 1;
6748 
6749  while(IsLCAtHV(26, HLoc, (VLoc + DownStep)))
6750  {
6751  TrackMapKeyPair.first = HLoc;
6752  TrackMapKeyPair.second = VLoc + DownStep;
6753  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
6754  if(AllRoutes->GetRouteTypeAndNumber(21, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
6755  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
6756  {
6757  Utilities->CallLogPop(1934);
6758  return true;
6759  }
6760  if(TrackElementAt(868, TrackMapPtr->second).TrainIDOnElement != -1)
6761  {
6762  TrainPresent = true;
6763  Utilities->CallLogPop(1935);
6764  return true;
6765  }
6766  DownStep++;
6767  }
6768 // find leftmost LC
6769  int LeftStep = 0;
6770 
6771  while(IsLCAtHV(27, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6772  {
6773  TrackMapKeyPair.first = HLoc + LeftStep;
6774  TrackMapKeyPair.second = VLoc;
6775  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
6776  if(AllRoutes->GetRouteTypeAndNumber(22, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
6777  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
6778  {
6779  Utilities->CallLogPop(1936);
6780  return true;
6781  }
6782  if(TrackElementAt(869, TrackMapPtr->second).TrainIDOnElement != -1)
6783  {
6784  TrainPresent = true;
6785  Utilities->CallLogPop(1937);
6786  return true;
6787  }
6788  LeftStep--;
6789  }
6790 // now find rightmost LC, opening them all (to trains) in turn
6791  int RightStep = 1;
6792 
6793  while(IsLCAtHV(28, (HLoc + RightStep), VLoc))
6794  {
6795  TrackMapKeyPair.first = HLoc + RightStep;
6796  TrackMapKeyPair.second = VLoc;
6797  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
6798  if(AllRoutes->GetRouteTypeAndNumber(23, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
6799  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
6800  {
6801  Utilities->CallLogPop(1938);
6802  return true;
6803  }
6804  if(TrackElementAt(870, TrackMapPtr->second).TrainIDOnElement != -1)
6805  {
6806  TrainPresent = true;
6807  Utilities->CallLogPop(1939);
6808  return true;
6809  }
6810  RightStep++;
6811  }
6812  Utilities->CallLogPop(1940);
6813  return false;
6814 }
6815 
6816 // ---------------------------------------------------------------------------
6817 
6818 Graphics::TBitmap *TTrack::GetFilletGraphic(int Caller, TTrackElement TrackElement)
6819 {
6820  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFilletGraphic," + TrackElement.LogTrack(4));
6821  if(TrackElement.TrackType != Points)
6822  {
6823  throw Exception("Error, Wrong track type in GetFilletGraphic");
6824  }
6825  if(TrackElement.SpeedTag < 28)
6826  {
6827  Utilities->CallLogPop(521);
6828  return RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute];
6829  }
6830  else if(TrackElement.SpeedTag < 132)
6831  {
6832  Utilities->CallLogPop(522);
6833 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
6834  return RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute];
6835  }
6836  else
6837  {
6838  Utilities->CallLogPop(1537);
6839  return RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute];
6840  }
6841 }
6842 
6843 // ---------------------------------------------------------------------------
6844 
6846 {
6847  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAllTrainIDElements");
6848  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
6849  {
6850  TrackVector.at(x).TrainIDOnElement = -1;
6851  TrackVector.at(x).TrainIDOnBridgeTrackPos01 = -1;
6852  TrackVector.at(x).TrainIDOnBridgeTrackPos23 = -1;
6853  }
6854  Utilities->CallLogPop(1342);
6855 }
6856 
6857 // ---------------------------------------------------------------------------
6858 
6859 void TTrack::GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
6860 /*
6861  Converts the screen position to the true (without offsets) HLoc, VLoc 16 x 16 square that the screen position lies within
6862 */
6863 {
6864  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackLocsFromScreenPos," + AnsiString(ScreenPosH) + "," +
6865  AnsiString(ScreenPosV));
6866  HLoc = div(ScreenPosH, 16).quot + Display->DisplayOffsetH;
6867  VLoc = div(ScreenPosV, 16).quot + Display->DisplayOffsetV;
6868 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
6869  Utilities->CallLogPop(535);
6870 }
6871 
6872 // ---------------------------------------------------------------------------
6873 
6874 void TTrack::GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
6875 /*
6876  Converts the screen position to the true (without offsets) position
6877 */
6878 {
6879  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTruePositionsFromScreenPos," + AnsiString(ScreenPosH) + "," +
6880  AnsiString(ScreenPosV));
6881  HPos = ScreenPosH + (Display->DisplayOffsetH * 16);
6882  VPos = ScreenPosV + (Display->DisplayOffsetV * 16);
6883  Utilities->CallLogPop(536);
6884 }
6885 
6886 // ---------------------------------------------------------------------------
6887 
6888 void TTrack::GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
6889 {
6890  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetScreenPositionsFromTruePos," + AnsiString(HPosTrue) + "," +
6891  AnsiString(VPosTrue));
6892  ScreenPosH = HPosTrue - (Display->DisplayOffsetH * 16);
6893  ScreenPosV = VPosTrue - (Display->DisplayOffsetV * 16);
6894  Utilities->CallLogPop(537);
6895 }
6896 
6897 // ---------------------------------------------------------------------------
6898 
6899 void TTrack::CheckMapAndTrack(int Caller) // test
6900 {
6901  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndTrack");
6902  int Zeroes = 0;
6903  bool FoundFlag;
6904 
6905  for(unsigned int a = 0; a < TrackVector.size(); a++)
6906  {
6907  TTrackElement CheckElement = Track->TrackVector.at(a);
6908  if(CheckElement.SpeedTag == 0)
6909  {
6910  Zeroes++; // zeroed elements not saved in map
6911  }
6912  else
6913  {
6914  int MapVecPos = GetVectorPositionFromTrackMap(16, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
6915  if(!FoundFlag)
6916  {
6917  throw Exception("CheckMapAndTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
6918  " in TrackMap, Caller=" + (AnsiString)Caller);
6919  }
6920  if(MapVecPos != (int)a)
6921  {
6922  throw Exception("CheckMapAndTrack Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
6923  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)MapVecPos + " TrackVectorPos value=" + (AnsiString)a + " Caller=" +
6924  (AnsiString)Caller);
6925  }
6926  }
6927  }
6928  if(TrackVector.size() != (TrackMap.size() + Zeroes))
6929  {
6930  throw Exception("CheckMapAndTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
6931  " Caller=" + (AnsiString)Caller);
6932  }
6933  Utilities->CallLogPop(538);
6934  return;
6935 }
6936 
6937 // ---------------------------------------------------------------------------
6938 
6939 void TTrack::CheckMapAndInactiveTrack(int Caller) // test
6940 {
6941  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndInactiveTrack");
6942  bool FoundFlag;
6943  TIMPair InactivePair;
6944 
6945  for(unsigned int a = 0; a < InactiveTrackVector.size(); a++)
6946  {
6947  TTrackElement CheckElement = Track->InactiveTrackVector.at(a);
6948  InactivePair = GetVectorPositionsFromInactiveTrackMap(7, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
6949  if(!FoundFlag)
6950  {
6951  throw Exception("CheckMapAndInactiveTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
6952  " in InactiveMap, Caller=" + (AnsiString)Caller);
6953  }
6954  if((InactivePair.first != a) && (InactivePair.second != a))
6955  {
6956  throw Exception("CheckMapAndInactiveTrack Error - InactiveMapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
6957  (AnsiString)CheckElement.VLoc + " Inactive Map values=" + (AnsiString)InactivePair.first + " and " + (AnsiString)InactivePair.second +
6958  " InactiveTrackVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
6959  }
6960  }
6961  if(InactiveTrackVector.size() != InactiveTrack2MultiMap.size())
6962  {
6963  throw Exception("CheckMapAndInactiveTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
6964  " Caller=" + (AnsiString)Caller);
6965  }
6966  Utilities->CallLogPop(539);
6967 }
6968 
6969 // ---------------------------------------------------------------------------
6970 
6971 void TTrack::CheckGapMap(int Caller) // test
6972 {
6973  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckGapMap");
6974  int Position1, Position2;
6975  TTrackElement TrackElement1, TrackElement2;
6976  TGapMapIterator GapMapPtr;
6977 
6978  if(!GapMap.empty())
6979  {
6980  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
6981  {
6982  int HLoc1 = GapMapPtr->first.first;
6983  int VLoc1 = GapMapPtr->first.second;
6984  int HLoc2 = GapMapPtr->second.first;
6985  int VLoc2 = GapMapPtr->second.second;
6986  if(!FindNonPlatformMatch(14, HLoc1, VLoc1, Position1, TrackElement1))
6987  {
6988  throw Exception("Failed to find H & V for gap1, GapMap in error");
6989  }
6990  if(!FindNonPlatformMatch(15, HLoc2, VLoc2, Position2, TrackElement2))
6991  {
6992  throw Exception("Failed to find H & V for gap2, GapMap in error");
6993  }
6994  if(TrackElementAt(17, Position1).TrackType != GapJump)
6995  {
6996  throw Exception("Element at Pos1 not a gap, GapMap in error");
6997  }
6998  if(TrackElementAt(18, Position2).TrackType != GapJump)
6999  {
7000  throw Exception("Element at Pos2 not a gap, GapMap in error");
7001  }
7002  }
7003  }
7004  unsigned int GapCount = 0;
7005 
7006  for(unsigned int a = 0; a < TrackVector.size(); a++)
7007  {
7008  TTrackElement CheckElement = Track->TrackVector.at(a);
7009  if(CheckElement.TrackType == GapJump)
7010  GapCount++;
7011  }
7012  if((GapMap.size() * 2) != GapCount)
7013  {
7014  throw Exception("GapMap Error - Map Size * 2 =" + (AnsiString)(GapMap.size() * 2) + " GapCount=" + (AnsiString)GapCount + " Caller=" +
7015  (AnsiString)Caller);
7016  }
7017  Utilities->CallLogPop(540);
7018 }
7019 
7020 // ---------------------------------------------------------------------------
7021 
7022 void TTrack::SetElementID(int Caller, TTrackElement &TrackElement)
7023 {
7024  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetElementID," + TrackElement.LogTrack(5));
7025  if((TrackElement.HLoc == -2000000000) || (TrackElement.VLoc == -2000000000))
7026  {
7027  if(TrackFinished)
7028  {
7029  throw Exception("Error - TrackFinished with erase element still present");
7030  }
7031  Utilities->CallLogPop(541);
7032  return; // erased element, can't set ID
7033  }
7034  AnsiString IDString;
7035 
7036  if(TrackElement.HLoc < 0)
7037  IDString = "N" + AnsiString(abs(TrackElement.HLoc)) + "-";
7038  else
7039  IDString = AnsiString(TrackElement.HLoc) + "-";
7040  if(TrackElement.VLoc < 0)
7041  IDString += "N" + AnsiString(abs(TrackElement.VLoc));
7042  else
7043  IDString += AnsiString(TrackElement.VLoc);
7044  TrackElement.ElementID = IDString;
7045  Utilities->CallLogPop(542);
7046 }
7047 
7048 // ---------------------------------------------------------------------------
7049 
7050 int TTrack::GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
7051 {
7052 // e.g. "8-13", "00008-13", "N43-N127", etc
7053  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorPositionFromString, + String");
7054  int DelimPos;
7055 
7056  for(int x = 1; x < String.Length() + 1; x++)
7057  {
7058  if(String.IsDelimiter("-", x))
7059  {
7060  DelimPos = x;
7061  break;
7062  }
7063  if(x == String.Length())
7064  {
7065  if(GiveMessages)
7066  ShowMessage("Error in track element identifier: <" + String + "> - no delimiter");
7067  Utilities->CallLogPop(543);
7068  return -1;
7069  }
7070  }
7071  if(DelimPos == 1)
7072  {
7073  if(GiveMessages)
7074  ShowMessage("Error in track element identifier: <" + String + "> - No Horizontal value");
7075  Utilities->CallLogPop(544);
7076  return -1;
7077  }
7078  if(DelimPos == String.Length())
7079  {
7080  if(GiveMessages)
7081  ShowMessage("Error in track element identifier <" + String + "> - No Vertical value");
7082  Utilities->CallLogPop(545);
7083  return -1;
7084  }
7085  if((String[String.Length()] < '0') || (String[String.Length()] > '9'))
7086  {
7087  if(GiveMessages)
7088  ShowMessage("Error in track element identifier <" + String + "> - Last value is not a number");
7089  Utilities->CallLogPop(1508);
7090  return -1;
7091  }
7092  int HLoc, VLoc;
7093 
7094  if(String.SubString(1, 1) != "N")
7095  {
7096  for(int x = 1; x < DelimPos; x++)
7097  {
7098  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7099  {
7100  if(GiveMessages)
7101  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
7102  Utilities->CallLogPop(546);
7103  return -1;
7104  }
7105  }
7106  }
7107  if(String.SubString(1, 1) == "N")
7108  {
7109  for(int x = 2; x < DelimPos; x++)
7110  {
7111  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7112  {
7113  if(GiveMessages)
7114  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
7115  Utilities->CallLogPop(763);
7116  return -1;
7117  }
7118  }
7119  }
7120  if(String.SubString(1, 1) == "N")
7121  HLoc = -(String.SubString(2, DelimPos - 2).ToInt());
7122  else
7123  HLoc = String.SubString(1, DelimPos - 1).ToInt();
7124 
7125  if(String.SubString(DelimPos + 1, 1) != "N")
7126  {
7127  for(int x = DelimPos + 1; x < String.Length() + 1; x++)
7128  {
7129  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7130  {
7131  if(GiveMessages)
7132  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
7133  Utilities->CallLogPop(547);
7134  return -1;
7135  }
7136  }
7137  }
7138  if(String.SubString(DelimPos + 1, 1) == "N")
7139  {
7140  for(int x = DelimPos + 2; x < String.Length() + 1; x++)
7141  {
7142  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7143  {
7144  if(GiveMessages)
7145  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
7146  Utilities->CallLogPop(764);
7147  return -1;
7148  }
7149  }
7150  }
7151  if(String.SubString(DelimPos + 1, 1) == "N")
7152  VLoc = -(String.SubString(DelimPos + 2, String.Length() - DelimPos - 1).ToInt());
7153  else
7154  VLoc = String.SubString(DelimPos + 1, String.Length() - DelimPos).ToInt();
7155 
7156  THVPair HVPair(HLoc, VLoc);
7157  TTrackMapIterator TrackMapPtr;
7158 
7159  TrackMapPtr = TrackMap.find(HVPair);
7160  if(TrackMapPtr == TrackMap.end())
7161  {
7162  if(GiveMessages)
7163  ShowMessage("No track element corresponding to track element identifier: <" + String + ">");
7164  Utilities->CallLogPop(548);
7165  return -1;
7166  }
7167  Utilities->CallLogPop(549);
7168  return TrackMapPtr->second;
7169 }
7170 
7171 // ---------------------------------------------------------------------------
7172 
7173 bool TTrack::CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
7174 /*
7175  True for linked properly at both ends
7176 */
7177 {
7178  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckFootCrossingLinks," + AnsiString(TrackElement.HLoc) + "," +
7179  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
7180  int HLoc = TrackElement.HLoc;
7181  int VLoc = TrackElement.VLoc;
7182 
7183  if((TrackElement.SpeedTag != 129) && (TrackElement.SpeedTag != 130) && (TrackElement.SpeedTag != 145) && (TrackElement.SpeedTag != 146))
7184  {
7185  Utilities->CallLogPop(1821);
7186  return false;
7187  }
7188  if(TrackElement.SpeedTag == 129) // vertical footbridge
7189  {
7190  // check top connection
7191  if(!(InactiveMapCheck(1, HLoc, VLoc, 76) // top plat
7192  || InactiveMapCheck(2, HLoc, VLoc - 1, 96) // concourse
7193  || InactiveMapCheck(3, HLoc, VLoc - 1, 77) // bot plat
7194  || ActiveMapCheck(4, HLoc, VLoc - 1, 129))) // vert footbridge
7195  {
7196  Utilities->CallLogPop(550);
7197  return false;
7198  }
7199  // check bottom connection
7200  else if(!(InactiveMapCheck(4, HLoc, VLoc, 77) // bot plat
7201  || InactiveMapCheck(5, HLoc, VLoc + 1, 96) // concourse
7202  || InactiveMapCheck(6, HLoc, VLoc + 1, 76) // top plat
7203  || ActiveMapCheck(1, HLoc, VLoc + 1, 129))) // vert footbridge
7204  {
7205  Utilities->CallLogPop(551);
7206  return false;
7207  }
7208  }
7209  if(TrackElement.SpeedTag == 145) // vertical underpass
7210  {
7211  // check top connection
7212  if(!(InactiveMapCheck(13, HLoc, VLoc, 76) // top plat
7213  || InactiveMapCheck(14, HLoc, VLoc - 1, 96) // concourse
7214  || InactiveMapCheck(15, HLoc, VLoc - 1, 77) // bot plat
7215  || ActiveMapCheck(5, HLoc, VLoc - 1, 145))) // vert u'pass
7216  {
7217  Utilities->CallLogPop(2114);
7218  return false;
7219  }
7220  // check bottom connection
7221  else if(!(InactiveMapCheck(16, HLoc, VLoc, 77) // bot plat
7222  || InactiveMapCheck(17, HLoc, VLoc + 1, 96) // concourse
7223  || InactiveMapCheck(18, HLoc, VLoc + 1, 76) // top plat
7224  || ActiveMapCheck(6, HLoc, VLoc + 1, 145))) // vert u'pass
7225  {
7226  Utilities->CallLogPop(2115);
7227  return false;
7228  }
7229  }
7230  if(TrackElement.SpeedTag == 130) // hor footbridge
7231  {
7232  // check left connection
7233  if(!(InactiveMapCheck(19, HLoc, VLoc, 78) // left plat
7234  || InactiveMapCheck(20, HLoc - 1, VLoc, 96) // concourse
7235  || InactiveMapCheck(21, HLoc - 1, VLoc, 79) // right plat
7236  || ActiveMapCheck(2, HLoc - 1, VLoc, 130))) // hor footbridge
7237  {
7238  Utilities->CallLogPop(552);
7239  return false;
7240  }
7241  // check right connection
7242  else if(!(InactiveMapCheck(22, HLoc, VLoc, 79) // right plat
7243  || InactiveMapCheck(23, HLoc + 1, VLoc, 96) // concourse
7244  || InactiveMapCheck(24, HLoc + 1, VLoc, 78) // left plat
7245  || ActiveMapCheck(3, HLoc + 1, VLoc, 130))) // hor footbridge
7246  {
7247  Utilities->CallLogPop(553);
7248  return false;
7249  }
7250  }
7251  if(TrackElement.SpeedTag == 146) // hor u'pass
7252  {
7253  // check left connection
7254  if(!(InactiveMapCheck(7, HLoc, VLoc, 78) // left plat
7255  || InactiveMapCheck(8, HLoc - 1, VLoc, 96) // concourse
7256  || InactiveMapCheck(9, HLoc - 1, VLoc, 79) // right plat
7257  || ActiveMapCheck(7, HLoc - 1, VLoc, 146))) // hor u'pass
7258  {
7259  Utilities->CallLogPop(2116);
7260  return false;
7261  }
7262  // check right connection
7263  else if(!(InactiveMapCheck(10, HLoc, VLoc, 79) // right plat
7264  || InactiveMapCheck(11, HLoc + 1, VLoc, 96) // concourse
7265  || InactiveMapCheck(12, HLoc + 1, VLoc, 78) // left plat
7266  || ActiveMapCheck(8, HLoc + 1, VLoc, 146))) // hor u'pass
7267  {
7268  Utilities->CallLogPop(2117);
7269  return false;
7270  }
7271  }
7272  Utilities->CallLogPop(554);
7273  return true;
7274 }
7275 
7276 // ---------------------------------------------------------------------------
7277 
7278 bool TTrack::InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
7279 /*
7280  return true if the SpeedTag present in the map at H & V
7281 */
7282 {
7283  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7284  AnsiString(SpeedTag));
7285  if(InactiveTrack2MultiMap.empty())
7286  {
7287  Utilities->CallLogPop(555);
7288  return false;
7289  }
7290  THVPair HVPair(HLoc, VLoc);
7292  TInactiveTrack2MultiMapIterator HVIt1 = IMEnd, HVIt2 = IMEnd;
7293  TInactiveTrackRange HVRange = InactiveTrack2MultiMap.equal_range(HVPair);
7294 
7295  if(HVRange.first == HVRange.second)
7296  {
7297  Utilities->CallLogPop(556);
7298  return false;
7299  }
7300  else
7301  HVIt1 = HVRange.first;
7302  TTrackElement Temp1, Temp2; // test
7303 
7304  Temp1 = InactiveTrackElementAt(8, HVIt1->second); // test
7305  if(--HVRange.second != HVRange.first)
7306  {
7307  HVIt2 = HVRange.second;
7308  Temp2 = InactiveTrackElementAt(9, HVIt2->second); // test
7309  }
7310  if((InactiveTrackElementAt(10, HVIt1->second).SpeedTag == SpeedTag) || ((HVIt2 != IMEnd) && (InactiveTrackElementAt(11,
7311  HVIt2->second).SpeedTag == SpeedTag)))
7312  {
7313  Utilities->CallLogPop(557);
7314  return true;
7315  }
7316  else
7317  {
7318  Utilities->CallLogPop(558);
7319  return false;
7320  }
7321 }
7322 
7323 // ---------------------------------------------------------------------------
7324 
7325 bool TTrack::ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
7326 /*
7327  return true if the SpeedTag present in the map at H & V
7328 */
7329 {
7330  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ActiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7331  AnsiString(SpeedTag));
7332  if(TrackMap.empty())
7333  {
7334  Utilities->CallLogPop(559);
7335  return false;
7336  }
7337  THVPair HVPair(HLoc, VLoc);
7338  TTrackMapIterator End = TrackMap.end();
7339  TTrackMapIterator It = End;
7340 
7341  It = TrackMap.find(HVPair);
7342  if((It != End) && (TrackElementAt(19, It->second).SpeedTag == SpeedTag))
7343  {
7344  Utilities->CallLogPop(560);
7345  return true;
7346  }
7347  else
7348  {
7349  Utilities->CallLogPop(561);
7350  return false;
7351  }
7352 }
7353 
7354 // ---------------------------------------------------------------------------
7355 
7356 void TTrack::EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
7357 {
7358 /*
7359  General:
7360  All platform, concourse, footcrossing & non-station named location elements are able to have a LocationName allocated, and track
7361  elements (including footcrossings) are able to have an ActiveTrackElementName allocated provided there is an adjacent platform or
7362  a NamedNonStationLocation.
7363  To set these names the user selects a single named location element (not a footcrossing), enters the name, and
7364  this is then allocated as a LocationName to all linked platform, concourse and footcrossing elements, and as an
7365  ActiveTrackElementName to all track elements adjacent to platforms (inc footcrossing tracks if (but only if) they have a
7366  platform at that location).
7367 
7368  Linked named location elements are those explained in TTrack::TTrack()
7369 
7370  Detail:
7371  Two containers are used for allocation of names - LNPendingList, and LNDone2MultiMap, each containing vector positions as
7372  integers and the Map using THVPairs as keys. An adjustment is made for the vector positions as follows:-
7373  inactive vector positions are stored as they are (since most NamedLocationElements are in the inactive vector), but active vector
7374  positions stored as (-1-True Position), so can hold both types in a single integer uniquely - not very elegant but it seems to
7375  work OK! e.g. TrackVector position 0 would be stored as -1, position n would be stored as -1-n. InactiveTrackVector position 0 would be stored as 0.
7376  To recover the true TrackVector position from a stored value the same rule applies, i.e. -1-stored value, equivalent to -1-(-1-original) = -1+1+original = original.
7377 
7378  The List holds elements that have still to be processed, and the Map holds elements that have been processed. On entering
7379  this function a single element should be in the List (normally from the user's selection but can also be from
7380  SearchForAndUpdateLocationName), and the Map is cleared within the function.
7381  A 'while' loop is entered if the List isn't empty, and the front element in it examined. All linked named location elements
7382  (platforms, concourses and footcrossings) that aren't already in either the Map or the List are first added to the List using
7383  AdjElement, then the element itself has it's LocationName set, and any relevant track elements at the same H & V (i.e. adjacent
7384  to a platform) have their ActiveTrackElementName set using AddName. The element is then inserted into the Map and erased from the List.
7385  In this way the list builds up while there are linked elements to be added, but reduces to zero when all are added and processing
7386  moves them into the Map. At the end all linked elements are in the Map.
7387 
7388  Finally any other element that isn't in the Map, i.e. not linked to the current named location, that has the same name as a
7389  LocationName or ActiveTrackElementName, has it erased. This is to allow for deletion of named location elements that split an existing
7390  named location - only one of the sides (selected by whichever the program finds first - the user can't select it) retains the name.
7391 */
7392 
7393 // AnsiString TestString = "H,V,Tag,List Size,DoneMultiMap Size,CurrentElementAddress,MultiMapEntryAddress";//test
7394 // Display->FileDiagnostics(TestString);//test
7395 
7396  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EnterLocationName," + LocationName);
7397  AnsiString TestString1, TestString2; // test
7398 
7399  Track->LNDone2MultiMap.clear();
7400  if(LNPendingList.size() != 1)
7401  {
7402  throw Exception("LNPendingList size not 1 on entry");
7403  }
7404  int CurrentElementNumber; //new after 2.4.3 due to error the JK found (Discord 9/7/20). See note below after 'if(AddingElements)' where CurrentElementNumber is used.
7405  while(!LNPendingList.empty())
7406  {
7407  CurrentElementNumber = LNPendingList.front();
7408  TTrackVectorIterator CurrentElement = GetTrackVectorIteratorFromNamePosition(1, CurrentElementNumber);
7409  int NewElement; // = 2000000000; //marker for unused //not needed after v1.1.4
7410  int H = CurrentElement->HLoc;
7411  int V = CurrentElement->VLoc;
7412  int Tag = CurrentElement->SpeedTag;
7413  if(Tag == 76) // top plat
7414  {
7415  // AdjElement checks if there is an element matching Tag at H & V that isn't already in LNDone2MultiMap or LNPendingList,
7416  // & returns true if so with the adjusted vector position in NewElement. It checks the appropriate vector
7417  // depending on the SpeedTag value (footcrossings in active vector, rest in inactive vector),
7418  for(int x = 0; x < 25; x++)
7419  {
7420  if(AdjElement(1, H + Tag76Array[x][0], V + Tag76Array[x][1], Tag76Array[x][2], NewElement))
7421  {
7422  LNPendingList.insert(LNPendingList.end(), NewElement);
7423  }
7424  }
7425  }
7426  else if(Tag == 77) // bot plat
7427  {
7428  for(int x = 0; x < 25; x++)
7429  {
7430  if(AdjElement(2, H + Tag77Array[x][0], V + Tag77Array[x][1], Tag77Array[x][2], NewElement))
7431  {
7432  LNPendingList.insert(LNPendingList.end(), NewElement);
7433  }
7434  }
7435  }
7436  else if(Tag == 78) // l plat
7437  {
7438  for(int x = 0; x < 25; x++)
7439  {
7440  if(AdjElement(3, H + Tag78Array[x][0], V + Tag78Array[x][1], Tag78Array[x][2], NewElement))
7441  {
7442  LNPendingList.insert(LNPendingList.end(), NewElement);
7443  }
7444  }
7445  }
7446  else if(Tag == 79) // r plat
7447  {
7448  for(int x = 0; x < 25; x++)
7449  {
7450  if(AdjElement(4, H + Tag79Array[x][0], V + Tag79Array[x][1], Tag79Array[x][2], NewElement))
7451  {
7452  LNPendingList.insert(LNPendingList.end(), NewElement);
7453  }
7454  }
7455  }
7456  else if(Tag == 96) // conc
7457  {
7458  for(int x = 0; x < 28; x++)
7459  {
7460  if(AdjElement(5, H + Tag96Array[x][0], V + Tag96Array[x][1], Tag96Array[x][2], NewElement))
7461  {
7462  LNPendingList.insert(LNPendingList.end(), NewElement);
7463  }
7464  }
7465  }
7466  else if(Tag == 129) // vert footbridge
7467  {
7468  for(int x = 0; x < 8; x++)
7469  {
7470  if(AdjElement(6, H + Tag129Array[x][0], V + Tag129Array[x][1], Tag129Array[x][2], NewElement))
7471  {
7472  LNPendingList.insert(LNPendingList.end(), NewElement);
7473  }
7474  }
7475  }
7476  else if(Tag == 130) // hor footbridge
7477  {
7478  for(int x = 0; x < 8; x++)
7479  {
7480  if(AdjElement(7, H + Tag130Array[x][0], V + Tag130Array[x][1], Tag130Array[x][2], NewElement))
7481  {
7482  LNPendingList.insert(LNPendingList.end(), NewElement);
7483  }
7484  }
7485  }
7486  else if(Tag == 131) // named location
7487  {
7488  for(int x = 0; x < 4; x++)
7489  {
7490  if(AdjElement(8, H + Tag131Array[x][0], V + Tag131Array[x][1], Tag131Array[x][2], NewElement))
7491  {
7492  LNPendingList.insert(LNPendingList.end(), NewElement);
7493  }
7494  }
7495  }
7496  else if(Tag == 145) // v u'pass
7497  {
7498  for(int x = 0; x < 8; x++)
7499  {
7500  if(AdjElement(9, H + Tag145Array[x][0], V + Tag145Array[x][1], Tag145Array[x][2], NewElement))
7501  {
7502  LNPendingList.insert(LNPendingList.end(), NewElement);
7503  }
7504  }
7505  }
7506  else if(Tag == 146) // h u'pass
7507  {
7508  for(int x = 0; x < 8; x++)
7509  {
7510  if(AdjElement(10, H + Tag146Array[x][0], V + Tag146Array[x][1], Tag146Array[x][2], NewElement))
7511  {
7512  LNPendingList.insert(LNPendingList.end(), NewElement);
7513  }
7514  }
7515  }
7516  // below new at v1.1.0 but condition changed at v1.1.4 as interfered with name changes for single element locations
7517 // if(NewElement != 2000000000) //adjacent element found & new element inserted, check if a (different) name already allocated and if so erase it from text vector
7518  if(AddingElements)
7519  {
7520  int HPos, VPos; // not used but needed for FindText function
7521  if(CurrentElementNumber > -1) //up to & including 2.4.2 this was NewElement, which was the last one added during LNPendingList building above, so it could be
7522  //repeatedly selected rather than the element under examination (LNPendingList.front()) & the front element text name wouldn't be erased.
7523  //Using CurrentElementNumber ensures that all elements are examined & have names erased if present
7524  {
7525  AnsiString ExistingName = InactiveTrackElementAt(118, CurrentElementNumber).LocationName;//existing name of CurrentElement
7526  if((ExistingName != "") && (ExistingName != LocationName))
7527  {
7528  if(LocationNameMultiMap.find(ExistingName) == Track->LocationNameMultiMap.end())
7529  {} // name not in LocationNameMultiMap, so don't erase from TextVector
7530  else if(TextHandler->FindText(4, ExistingName, HPos, VPos)) // can't use 'EraseLocationNameText' as that function is in TInterface
7531  {
7532  if(TextHandler->TextErase(10, HPos, VPos, ExistingName))
7533  {;
7534  } // condition not used
7535  }
7536  }
7537  }
7538  }
7539 
7540  AddName(1, CurrentElement, LocationName); // add location name to current element, + timetable name to any
7541  // track at that loc
7542  THVPair HVPair(H, V);
7543  TLNDone2MultiMapEntry LNDone2MultiMapEntry;
7544  LNDone2MultiMapEntry.first = HVPair;
7545  LNDone2MultiMapEntry.second = LNPendingList.front();
7546  LNDone2MultiMap.insert(LNDone2MultiMapEntry);
7547  LNPendingList.erase(LNPendingList.begin());
7548  }
7549 
7550 // search all name multimap for same name where corresponding active elements don't appear in
7551 // LNDone2MultiMap & erase the name for all elements at that H & V in both active & inactive vectors
7552 
7553  TLocationNameMultiMapIterator SNIterator;
7554  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
7555  bool FoundFlag, ErasedFlag = false;
7556 
7557  if(SNRange.first != SNRange.second)
7558  {
7559  SNRange.first--; // now pointing to before the first
7560  SNRange.second--; // now pointing to the last
7561  for(SNIterator = SNRange.second; SNIterator != SNRange.first; SNIterator--)
7562  // Same elements are in Done map as in name map
7563  {
7564  if(!ElementInLNDone2MultiMap(1, SNIterator->second))
7565  {
7566  ErasedFlag = true;
7567  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(2, SNIterator->second);
7568  TVIt->LocationName = "";
7569  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
7570  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform)
7571  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
7572  {
7573  int Position = GetVectorPositionFromTrackMap(17, TVIt->HLoc, TVIt->VLoc, FoundFlag);
7574  if(FoundFlag)
7575  {
7576  TrackElementAt(20, Position).LocationName = "";
7577  TrackElementAt(21, Position).ActiveTrackElementName = "";
7578  }
7579  }
7580  // erase name in name map
7581 // ChangeLocationNameMultiMapEntry("", SNIterator); can't use this as interferes with the iterators
7582  }
7583  }
7584  }
7585  if(ErasedFlag)
7587  if(TrackFinished)
7589 // set here as well as in LinkTrack so don't have to link track just because a name added
7590 // if track not finished then will be set when track validated
7591 
7592 // Rebuild ContinuationNameMap - added at v2.6.1 due to error found by Andrekoener & notified by discord on 16/12/20
7593 // error was that if a continuation name was changed and a timetable stopping place included that new name then ContinuationNameMap wouldn't be rebuilt
7594 // so the timetable would validate and load and the name would appear in the dropdown list. The reason was that ContinuationNameMap was only built in TryToLinkTrack,
7595 // so if that isn't called (as it isn't for a name change) then the error wouldn't be seen. However next time the railway was loaded TryToLinkTrack was called
7596 // so the error would be seen.
7597 // This inclusion rebuilds ContinuationNameMap whenever a name is entered or changed so the error can no longer be hidden.
7598  std::pair<AnsiString, char>TempMapPair;
7599 
7600  ContinuationNameMap.clear();
7601  for(int x = 0; x < Track->TrackVectorSize(); x++)
7602  {
7603  if((Track->TrackVector.at(x).TrackType == Continuation) && (Track->TrackVector.at(x).ActiveTrackElementName != ""))
7604  {
7605  TempMapPair.first = Track->TrackVector.at(x).ActiveTrackElementName;
7606  TempMapPair.second = 'x'; // unused
7607  ContinuationNameMap.insert(TempMapPair);
7608  }
7609  }
7610 //end of addition
7611  CheckLocationNameMultiMap(1); // test
7612  Utilities->CallLogPop(562);
7613 }
7614 
7615 // ---------------------------------------------------------------------------
7616 
7617 bool TTrack::AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
7618 /*
7619  Looks for a FixedNamedLocationElement at H & V with SpeedTag, and if found and not already present in either the
7620  LNDone2MultiMap or the LNPendingList returns an int corresponding to the adjusted vector position.
7621 */
7622 {
7623  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7624  AnsiString(SpeedTag));
7625  if(!NamedLocationElementAt(2, HLoc, VLoc))
7626  {
7627  Utilities->CallLogPop(948);
7628  return false;
7629  }
7630  bool FoundFlag;
7631  int Position = -1;
7632  TIMPair IMPair;
7633 
7634  if((SpeedTag == 129) || (SpeedTag == 130) || (SpeedTag == 145) || (SpeedTag == 146)) // footcrossing - only in active vector
7635  {
7636  Position = GetVectorPositionFromTrackMap(18, HLoc, VLoc, FoundFlag);
7637  if(FoundFlag)
7638  {
7639  if(TrackElementAt(22, Position).SpeedTag == SpeedTag)
7640  {
7641  int MapPos = -1 - Position; // MapPos is the adjusted entry in the list & map
7642  if(!ElementInLNDone2MultiMap(2, MapPos) && !ElementInLNPendingList(1, MapPos))
7643  // don't allow duplicates in either list, or processing takes a lot longer
7644  {
7645  FoundElement = MapPos;
7646  Utilities->CallLogPop(563);
7647  return true;
7648  }
7649  }
7650  }
7651  }
7652  else
7653  {
7654  IMPair = GetVectorPositionsFromInactiveTrackMap(8, HLoc, VLoc, FoundFlag);
7655  if(FoundFlag)
7656  {
7657  if(InactiveTrackElementAt(12, IMPair.first).SpeedTag == SpeedTag)
7658  {
7659  if(!ElementInLNDone2MultiMap(3, IMPair.first) && !ElementInLNPendingList(2, IMPair.first))
7660  {
7661  FoundElement = IMPair.first;
7662  Utilities->CallLogPop(564);
7663  return true;
7664  }
7665  }
7666  else if(InactiveTrackElementAt(13, IMPair.second).SpeedTag == SpeedTag)
7667  {
7668  if(!ElementInLNDone2MultiMap(4, IMPair.second) && !ElementInLNPendingList(3, IMPair.second))
7669  {
7670  FoundElement = IMPair.second;
7671  Utilities->CallLogPop(565);
7672  return true;
7673  }
7674  }
7675  }
7676  }
7677  Utilities->CallLogPop(566);
7678  return false;
7679 }
7680 
7681 // ---------------------------------------------------------------------------
7682 
7683 void TTrack::AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
7684 /*
7685  Add location name to TrackElement and ActiveTrackElementName to any elements in trackmap
7686  at same H & V if TrackElement is a Platform or named non-station location. Also update LocationNameMultiMap
7687  with the new name
7688 */
7689 {
7690  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddName," + TrackElement->LogTrack(6) + "," + Name);
7691  AnsiString OldName = TrackElement->LocationName, ErrorString; // declare new AnsiStrings OldName (set to existing name) & ErrorString
7692 
7693  TrackElement->LocationName = Name; // covers all FixedNamedLocationElement whichever vector they are in
7694  int HLoc = TrackElement->HLoc;
7695  int VLoc = TrackElement->VLoc;
7696  bool FoundFlag;
7697 
7698  if((TrackElement->TrackType == Platform) || (TrackElement->TrackType == NamedNonStationLocation))
7699  // only have timetable names for adjacent platforms & named locations
7700  {
7701  int Position = GetVectorPositionFromTrackMap(19, HLoc, VLoc, FoundFlag);
7702  if(FoundFlag)
7703  {
7704  TrackElementAt(23, Position).ActiveTrackElementName = Name;
7705  }
7706  }
7707  TLocationNameMultiMapIterator SNIterator = FindNamedElementInLocationNameMultiMap(4, OldName, TrackElement, ErrorString);
7708 
7709  if(ErrorString != "")
7710  {
7711  throw Exception(ErrorString + " in AddName for OldName == " + OldName);
7712  }
7713  ChangeLocationNameMultiMapEntry(1, Name, SNIterator); // OK, can use it here as not in an iterator loop
7714  CheckLocationNameMultiMap(2); // test
7715  Utilities->CallLogPop(567);
7716 }
7717 
7718 // ---------------------------------------------------------------------------
7719 
7720 bool TTrack::ElementInLNDone2MultiMap(int Caller, int MapPos)
7721 /*
7722  Examines LNDone2MultiMap to see whether the MapPos value is present, and returns true if so.
7723 */
7724 {
7725  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNDone2MultiMap," + AnsiString(MapPos));
7726  if(LNDone2MultiMap.empty())
7727  {
7728  Utilities->CallLogPop(568);
7729  return false;
7730  }
7731  TLNDone2MultiMapIterator LNDone2MultiMapIterator;
7732 
7733  for(LNDone2MultiMapIterator = LNDone2MultiMap.begin(); LNDone2MultiMapIterator != LNDone2MultiMap.end(); LNDone2MultiMapIterator++)
7734  {
7735  if(LNDone2MultiMapIterator->second == MapPos)
7736  {
7737  Utilities->CallLogPop(569);
7738  return true;
7739  }
7740  }
7741  Utilities->CallLogPop(570);
7742  return false;
7743 }
7744 
7745 // ---------------------------------------------------------------------------
7746 
7747 bool TTrack::ElementInLNPendingList(int Caller, int MapPos)
7748 /*
7749  Examines LNPendingList to see whether the MapPos value is present, and returns true if so.
7750 */
7751 {
7752  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNPendingList," + AnsiString(MapPos));
7753  if(LNPendingList.empty())
7754  {
7755  Utilities->CallLogPop(571);
7756  return false;
7757  }
7758  TLNPendingListIterator LNPendingListIterator;
7759 
7760  for(LNPendingListIterator = LNPendingList.begin(); LNPendingListIterator != LNPendingList.end(); LNPendingListIterator++)
7761  {
7762  if(*LNPendingListIterator == MapPos)
7763  {
7764  Utilities->CallLogPop(572);
7765  return true;
7766  }
7767  }
7768  Utilities->CallLogPop(573);
7769  return false;
7770 }
7771 
7772 // ---------------------------------------------------------------------------
7773 
7774 bool TTrack::NamedLocationElementAt(int Caller, int HLoc, int VLoc)
7775 /*
7776  Examines element at H & V, and returns true if its FixedNamedLocationElement bool is true
7777 */
7778 {
7779  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NamedLocationElementAt," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7780  THVPair HVPair(HLoc, VLoc);
7781  TTrackMapIterator TrackMapPtr = TrackMap.find(HVPair);
7782  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(HVPair);
7783 
7784  if(TrackMapPtr != TrackMap.end()) // =end() if not found
7785  {
7786  if(TrackElementAt(24, TrackMapPtr->second).FixedNamedLocationElement)
7787  {
7788  Utilities->CallLogPop(574);
7789  return true;
7790  }
7791  }
7792  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
7793  // may be 2 platforms at location but if so both FixedNamedLocationElement bools will be set, so only need to find one
7794  {
7795  if(InactiveTrackElementAt(14, InactiveTrack2MultiMapIterator->second).FixedNamedLocationElement)
7796  {
7797  Utilities->CallLogPop(575);
7798  return true;
7799  }
7800  }
7801  Utilities->CallLogPop(576);
7802  return false;
7803 }
7804 
7805 // ---------------------------------------------------------------------------
7806 
7807 bool TTrack::LocationNameAllocated(int Caller, AnsiString LocationName) // true if a non-empty LocationName found in LocationNameMultiMap
7808 {
7809  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationNameAllocated," + LocationName);
7810  if(Track->LocationNameMultiMap.find(LocationName) != Track->LocationNameMultiMap.end())
7811  {
7812  Utilities->CallLogPop(1953);
7813  return true;
7814  }
7815  Utilities->CallLogPop(1954);
7816  return false;
7817 }
7818 
7819 // ---------------------------------------------------------------------------
7820 
7821 bool TTrack::DuplicatedLocationName(int Caller, bool GiveMessage)
7822 //examines LocationNameMultiMap and returns true if there are two or more locations with the same name - added at v2.6.1 to cater for Bill78's new .dev file merge
7823 //program and used when try to save as a .rly file
7824 {
7825  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DuplicatedLocationName");
7828  if(LocationNameMultiMap.empty()) //no names so no duplicates
7829  {
7830  Utilities->CallLogPop(2254);
7831  return false;
7832  }
7833  AnsiString NameBeingChecked = LocationNameMultiMap.begin()->first; //first name to start with
7834  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked);
7836  {
7837  if(GiveMessage)
7838  {
7839  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
7840  }
7841  Utilities->CallLogPop(2255);
7842  return true;
7843  }
7844  while(LNMMRg.second != LocationNameMultiMap.end()) //here LNMMRg still set to earlier name
7845  {
7846  NameBeingChecked = LNMMRg.second->first;
7847  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked); //here LNMMRg is the new range
7849  {
7850  if(GiveMessage)
7851  {
7852  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
7853  }
7854  Utilities->CallLogPop(2256);
7855  return true;
7856  }
7857  }
7858  Utilities->CallLogPop(2257);
7859  return false; //OK, no duplicates
7860 }
7861 
7862 // ---------------------------------------------------------------------------
7863 
7865 {
7866  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateHVPairsLinkedMapAndNoDuplicates");
7867  THVPair HVPair;
7868  THVPairsLinkedMap HVPairsLinkedMap; //this is a map of HVPairs (so each is unique), each with a boolean marker, false for not linked and true for linked
7869  //for use in the duplicate check
7870  for(TLocationNameMultiMapIterator LNMMIt = LNMMRg.first; LNMMIt != LNMMRg.second; LNMMIt++) //populating the linked map
7871  {
7872  if(LNMMIt->second < 0) //active track element
7873  {
7874  HVPair.first = TrackElementAt(1011, (-1 - LNMMIt->second)).HLoc;
7875  HVPair.second = TrackElementAt(1012, (-1 - LNMMIt->second)).VLoc;
7876  }
7877  else //inactive track element
7878  {
7879  HVPair.first = InactiveTrackElementAt(134, LNMMIt->second).HLoc;
7880  HVPair.second = InactiveTrackElementAt(135, LNMMIt->second).VLoc;
7881  }
7882  HVPairsLinkedMap.insert(std::pair<THVPair, bool>(HVPair, false)); //set all bools to false initially
7883  }
7884  //All HVPairs now present in HVPairsLinkedMap for the specific location name
7885 
7886  //now need to identify all named elements that are linked either vertically or horizontally with the first one (could be any but must be just one)
7887  //so that at the end any that haven't been identified aren't linked and so represent a duplicated name
7888  //to do so need a list (works like LNPendingList) to hold all elements that haven't been checked for links
7889 
7890  std::list<THVPair> HVLinkedList;
7891 
7892  //set the first value to true and add it to the list
7893  HVPairsLinkedMap.begin()->second = true;
7894  HVLinkedList.push_back(HVPairsLinkedMap.begin()->first);
7895  //now enter a loop to examine the front pair in the list and set all linked bools to true, and if they weren't already true then add them to the back of the list for later
7896  //examination
7897  THVPair HVPairUnderExamination;
7898  THVPairsLinkedMap::iterator HVPLMIt;
7899  THVPair HVPairNew;
7900  while(!HVLinkedList.empty())
7901  {
7902  HVPairUnderExamination = HVLinkedList.front();
7903  HVLinkedList.pop_front();
7904  HVPairNew.first = HVPairUnderExamination.first;
7905  HVPairNew.second = HVPairUnderExamination.second - 1; //position directly above element
7906  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
7907  if(HVPLMIt != HVPairsLinkedMap.end())
7908  {
7909  if(!HVPLMIt->second)
7910  {
7911  HVLinkedList.push_back(HVPLMIt->first);
7912  }
7913  HVPLMIt->second = true;
7914  }
7915  HVPairNew.first = HVPairUnderExamination.first - 1;
7916  HVPairNew.second = HVPairUnderExamination.second; //position to the left of the element
7917  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
7918  if(HVPLMIt != HVPairsLinkedMap.end())
7919  {
7920  if(!HVPLMIt->second)
7921  {
7922  HVLinkedList.push_back(HVPLMIt->first);
7923  }
7924  HVPLMIt->second = true;
7925  }
7926  HVPairNew.first = HVPairUnderExamination.first;
7927  HVPairNew.second = HVPairUnderExamination.second + 1; //position under the element
7928  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
7929  if(HVPLMIt != HVPairsLinkedMap.end())
7930  {
7931  if(!HVPLMIt->second)
7932  {
7933  HVLinkedList.push_back(HVPLMIt->first);
7934  }
7935  HVPLMIt->second = true;
7936  }
7937  HVPairNew.first = HVPairUnderExamination.first + 1;
7938  HVPairNew.second = HVPairUnderExamination.second; //position to the right of the element
7939  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
7940  if(HVPLMIt != HVPairsLinkedMap.end())
7941  {
7942  if(!HVPLMIt->second)
7943  {
7944  HVLinkedList.push_back(HVPLMIt->first);
7945  }
7946  HVPLMIt->second = true;
7947  }
7948  }
7949 
7950  //at the end if any have a false bool then the name is duplicated so return false
7951  for(THVPairsLinkedMap::iterator HVPLMIt = HVPairsLinkedMap.begin(); HVPLMIt != HVPairsLinkedMap.end(); HVPLMIt++)
7952  {
7953  if(!HVPLMIt->second)
7954  {
7955  Utilities->CallLogPop(2258);
7956  return false;
7957  }
7958  }
7959  Utilities->CallLogPop(2259);
7960  return true;
7961 }
7962 
7963 // ---------------------------------------------------------------------------
7964 
7965 bool TTrack::TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
7966 /*
7967  Examines ActiveTrackElementNameMap and returns true if the LocationName is found and isn't "" (used to use LocationNameMultiMap)
7968 */
7969 
7970 {
7971  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TimetabledLocationNameAllocated," + LocationName);
7972  if(LocationName == "")
7973  {
7974  Utilities->CallLogPop(577);
7975  return false;
7976  }
7977 // new for v0.2b
7978 // compile ActiveTrackElementNameMap if !ActiveTrackElementNameMapCompiledFlag (added as a precaution, should be compiled when reach here)
7980  {
7981  TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
7982  ActiveTrackElementNameMap.clear();
7983  for(unsigned int x = 0; x < TrackVector.size(); x++)
7984  {
7985  if((TrackVector.at(x).ActiveTrackElementName != "") && (ContinuationNameMap.find(TrackVector.at(x).ActiveTrackElementName))
7986  == ContinuationNameMap.end())
7987  { // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
7988  ActiveTrackElementNameMapEntry.first = Track->TrackVector.at(x).ActiveTrackElementName;
7989  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
7990  ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
7991  }
7992  }
7994  }
7995  Utilities->CallLogPop(578);
7996  return (ActiveTrackElementNameMap.find(LocationName) != ActiveTrackElementNameMap.end());
7997 // end of new section
7998 // return (LocationNameMultiMap.find(LocationName) != LocationNameMultiMap.end());
7999 }
8000 
8001 // ---------------------------------------------------------------------------
8002 
8003 void TTrack::EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
8004 /*
8005  Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both active and inactive vectors) have the
8006  name erased both as a LocationName and a ActiveTrackElementName. The LocationNameMultiMap is also rebuilt to correspond to the
8007  new names in the vectors.
8008 */
8009 {
8010  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationAndActiveTrackElementNames," + LocationName);
8011  bool FoundFlag, ErasedFlag = false;
8012  TLocationNameMultiMapIterator SNIterator;
8013  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8014 
8015  if(SNRange.first != SNRange.second)
8016  {
8017  ErasedFlag = true;
8018  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
8019  {
8020  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(3, SNIterator->second);
8021  TVIt->LocationName = "";
8022  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8023  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform or namedlocation)
8024  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8025  {
8026  int Position = GetVectorPositionFromTrackMap(20, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8027  if(FoundFlag)
8028  {
8029  TrackElementAt(25, Position).LocationName = "";
8030  TrackElementAt(26, Position).ActiveTrackElementName = "";
8031  }
8032  }
8033  }
8034  }
8035  if(ErasedFlag)
8037  CheckLocationNameMultiMap(3); // test
8038  Utilities->CallLogPop(579);
8039 }
8040 
8041 // ---------------------------------------------------------------------------
8042 
8043 void TTrack::SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
8044 /*
8045  NB No longer used during EraseTrackElement, too long-winded - erase all name now if any part removed, user needs to re-enter
8046  Checks all locations that are adjacent to the one entered for linked named location elements, and if any LocationName is found
8047  in any of the linked elements that name is used for all elements that are now linked to it. The location entered doesn't
8048  need to be a FixedNamedLocationElement and there doesn't even need to be an element there. Used during EraseTrackElement (in which
8049  case the SpeedTag is that for the element that is erased) and PlotAndAddTrackElement, to bring the named location and timetable
8050  naming up to date with the deletion or insertion.
8051 */
8052 {
8053  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForAndUpdateLocationName," + AnsiString(HLoc) + "," +
8054  AnsiString(VLoc) + "," + AnsiString(SpeedTag));
8055  LNPendingList.clear();
8056  AnsiString LocationName;
8057  int MapPos;
8058  bool FoundFlag = 0;
8059 
8060 //first check if this element is inactive and named, and if so use its position and name (new at v2.6.0 to allow pasted named locations to name linked elements)
8061  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(30, HLoc, VLoc, FoundFlag);
8062  if(FoundFlag)
8063  {
8064  LocationName = InactiveTrackElementAt(132, IMPair.first).LocationName;
8065  if(LocationName != "")
8066  {
8067  LNPendingList.insert(Track->LNPendingList.end(), IMPair.first);
8068  EnterLocationName(13, LocationName, true);
8069  Utilities->CallLogPop(2251);
8070  return;
8071  }
8072  LocationName = InactiveTrackElementAt(133, IMPair.second).LocationName;
8073  if(LocationName != "")
8074  {
8075  LNPendingList.insert(Track->LNPendingList.end(), IMPair.second);
8076  EnterLocationName(14, LocationName, true);
8077  Utilities->CallLogPop(2252);
8078  return;
8079  }
8080  }
8081 //then check if this element is active and named, and if so use its position (-Pos-1) and name (new at v2.6.0 to allow pasted named locations to name linked elements)
8082 
8083  int Position = GetVectorPositionFromTrackMap(59, HLoc, VLoc, FoundFlag);
8084  if(FoundFlag)
8085  {
8086  LocationName = TrackElementAt(1004, Position).LocationName;
8087  if(LocationName != "")
8088  {
8089  int ModifiedPosition = -1 - Position;
8090  LNPendingList.insert(Track->LNPendingList.end(), ModifiedPosition);
8091  EnterLocationName(15, LocationName, true);
8092  Utilities->CallLogPop(2253);
8093  return;
8094  }
8095  }
8096 
8097  if(SpeedTag == 76) // top plat
8098  {
8099  for(int x = 0; x < 25; x++)
8100  {
8101  if(AdjNamedElement(1, HLoc + Tag76Array[x][0], VLoc + Tag76Array[x][1], Tag76Array[x][2], LocationName, MapPos))
8102  {
8103  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8104  EnterLocationName(3, LocationName, true);
8105  break;
8106  }
8107  }
8108  }
8109  else if(SpeedTag == 77) // bot plat
8110  {
8111  for(int x = 0; x < 25; x++)
8112  {
8113  if(AdjNamedElement(2, HLoc + Tag77Array[x][0], VLoc + Tag77Array[x][1], Tag77Array[x][2], LocationName, MapPos))
8114  {
8115  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8116  EnterLocationName(4, LocationName, true);
8117  break;
8118  }
8119  }
8120  }
8121  else if(SpeedTag == 78) // l plat
8122  {
8123  for(int x = 0; x < 25; x++)
8124  {
8125  if(AdjNamedElement(3, HLoc + Tag78Array[x][0], VLoc + Tag78Array[x][1], Tag78Array[x][2], LocationName, MapPos))
8126  {
8127  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8128  EnterLocationName(5, LocationName, true);
8129  break;
8130  }
8131  }
8132  }
8133  else if(SpeedTag == 79) // r plat
8134  {
8135  for(int x = 0; x < 25; x++)
8136  {
8137  if(AdjNamedElement(4, HLoc + Tag79Array[x][0], VLoc + Tag79Array[x][1], Tag79Array[x][2], LocationName, MapPos))
8138  {
8139  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8140  EnterLocationName(6, LocationName, true);
8141  break;
8142  }
8143  }
8144  }
8145  else if(SpeedTag == 96) // conc
8146  {
8147  for(int x = 0; x < 28; x++)
8148  {
8149  if(AdjNamedElement(5, HLoc + Tag96Array[x][0], VLoc + Tag96Array[x][1], Tag96Array[x][2], LocationName, MapPos))
8150  {
8151  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8152  EnterLocationName(7, LocationName, true);
8153  break;
8154  }
8155  }
8156  }
8157  else if(SpeedTag == 129) // vert footbridge
8158  {
8159  for(int x = 0; x < 8; x++)
8160  {
8161  if(AdjNamedElement(6, HLoc + Tag129Array[x][0], VLoc + Tag129Array[x][1], Tag129Array[x][2], LocationName, MapPos))
8162  {
8163  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8164  EnterLocationName(8, LocationName, true);
8165  break;
8166  }
8167  }
8168  }
8169  else if(SpeedTag == 130) // hor footbridge
8170  {
8171  for(int x = 0; x < 8; x++)
8172  {
8173  if(AdjNamedElement(7, HLoc + Tag130Array[x][0], VLoc + Tag130Array[x][1], Tag130Array[x][2], LocationName, MapPos))
8174  {
8175  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8176  EnterLocationName(9, LocationName, true);
8177  break;
8178  }
8179  }
8180  }
8181  else if(SpeedTag == 145) // vert u'pass
8182  {
8183  for(int x = 0; x < 8; x++)
8184  {
8185  if(AdjNamedElement(9, HLoc + Tag145Array[x][0], VLoc + Tag145Array[x][1], Tag145Array[x][2], LocationName, MapPos))
8186  {
8187  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8188  EnterLocationName(11, LocationName, true);
8189  break;
8190  }
8191  }
8192  }
8193  else if(SpeedTag == 146) // hor u'pass
8194  {
8195  for(int x = 0; x < 8; x++)
8196  {
8197  if(AdjNamedElement(10, HLoc + Tag146Array[x][0], VLoc + Tag146Array[x][1], Tag146Array[x][2], LocationName, MapPos))
8198  {
8199  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8200  EnterLocationName(12, LocationName, true);
8201  break;
8202  }
8203  }
8204  }
8205  else if(SpeedTag == 131) // named location
8206  {
8207  for(int x = 0; x < 4; x++)
8208  {
8209  if(AdjNamedElement(8, HLoc + Tag131Array[x][0], VLoc + Tag131Array[x][1], Tag131Array[x][2], LocationName, MapPos))
8210  {
8211  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8212  EnterLocationName(10, LocationName, true);
8213  break;
8214  }
8215  }
8216  }
8217 // AddName(HLoc, VLoc, LocationName);//don't need this now, EnterLocationName takes care of it
8218  Utilities->CallLogPop(580);
8219 }
8220 
8221 // ---------------------------------------------------------------------------
8222 
8223 bool TTrack::AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
8224 /*
8225  Used in SearchForAndUpdateLocationName to check for elements in TrackMap & InactiveTrackMap that match H, V & Tag, & returns
8226  true if a LocationName is found, and also returns the name and the adjusted vector position.
8227 */
8228 {
8229  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjNamedElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8230  AnsiString(SpeedTag));
8231  bool FoundFlag;
8232  TIMPair IMPair;
8233  TTrackVectorIterator TempElement;
8234  int Position;
8235 
8236  IMPair = GetVectorPositionsFromInactiveTrackMap(9, HLoc, VLoc, FoundFlag);
8237  if(FoundFlag)
8238  {
8239  if(InactiveTrackElementAt(15, IMPair.first).SpeedTag == SpeedTag)
8240  {
8241  TempElement = InactiveTrackVector.begin() + IMPair.first;
8242  if(TempElement->LocationName != "")
8243  {
8244  LocationName = TempElement->LocationName;
8245  FoundElement = IMPair.first;
8246  Utilities->CallLogPop(581);
8247  return true;
8248  }
8249  }
8250  else if(InactiveTrackElementAt(16, IMPair.second).SpeedTag == SpeedTag)
8251  {
8252  TempElement = InactiveTrackVector.begin() + IMPair.second;
8253  if(TempElement->LocationName != "")
8254  {
8255  LocationName = TempElement->LocationName;
8256  FoundElement = IMPair.second;
8257  Utilities->CallLogPop(582);
8258  return true;
8259  }
8260  }
8261  }
8262 
8263  Position = GetVectorPositionFromTrackMap(21, HLoc, VLoc, FoundFlag);
8264  if(FoundFlag)
8265  {
8266  if(TrackElementAt(27, Position).SpeedTag == SpeedTag)
8267  {
8268  TempElement = TrackVector.begin() + Position;
8269  if(TempElement->LocationName != "")
8270  {
8271  LocationName = TempElement->LocationName;
8272  FoundElement = -1 - Position;
8273  Utilities->CallLogPop(583);
8274  return true;
8275  }
8276  }
8277  }
8278  Utilities->CallLogPop(584);
8279  return false;
8280 }
8281 
8282 // ---------------------------------------------------------------------------
8283 
8284 void TTrack::CheckLocationNameMultiMap(int Caller) // test function
8285 {
8286 // check quantity in map & vectors match
8287  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckLocationNameMultiMap,");
8288  unsigned int Count = 0;
8289 
8290  if(SkipLocationNameMultiMapCheck) // renamed in v2.4.0 to skip check when pasting because fails as map elements not fully aligned until all pasted
8291  {
8292  Utilities->CallLogPop(2059);
8293  return;
8294  }
8295 
8296  AnsiString SName, TName, ErrorString;
8297 
8298  for(unsigned int x = 0; x < TrackVector.size(); x++)
8299  {
8300  if(TrackVector.at(x).FixedNamedLocationElement)
8301  {
8302  if(TrackVector.at(x).TrackType != FootCrossing)
8303  {
8304  throw Exception("Track element has FixedNamedLocationElement set but is not a footbridge/underpass in CheckLocationNameMultiMap, caller = " +
8305  AnsiString(Caller));
8306  }
8307  Count++;
8308  }
8309  }
8310  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
8311  {
8312  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
8313  {
8314  if((InactiveTrackVector.at(x).TrackType != Platform) && (InactiveTrackVector.at(x).TrackType != NamedNonStationLocation) &&
8315  (InactiveTrackVector.at(x).TrackType != Concourse))
8316  {
8317  throw Exception
8318  ("Inactive track element has FixedNamedLocationElement set but is not a platform, concourse or named location in CheckLocationNameMultiMap, caller = " +
8319  AnsiString(Caller));
8320  }
8321  Count++;
8322  }
8323  }
8324  if(LocationNameMultiMap.size() != Count)
8325  {
8326  throw Exception("LocationNameMultiMap size = " + AnsiString(LocationNameMultiMap.size()) + " & Count = " + AnsiString(Count) +
8327  " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
8328  }
8329 
8330 // check all entries in both vectors match entries in name multimap
8332 
8333  for(unsigned int x = 0; x < TrackVector.size(); x++)
8334  {
8335  if(TrackVector.at(x).FixedNamedLocationElement)
8336  {
8337  SName = TrackVector.at(x).LocationName;
8338  SNIt = FindNamedElementInLocationNameMultiMap(5, SName, TrackVector.begin() + x, ErrorString);
8339  if(ErrorString != "")
8340  {
8341  throw Exception(ErrorString + " in CheckLocationNameMultiMap for TrackVector check, caller = " + AnsiString(Caller));
8342  }
8343  if(SNIt->second != -1 - (int)x)
8344  {
8345  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
8346  AnsiString(Caller));
8347  }
8348  }
8349  // check corresponding platform for all Timetable entries that aren't empty
8350  TName = TrackVector.at(x).ActiveTrackElementName;
8351  TIMPair IMPair;
8352  bool FoundFlag = false;
8353  if(TName != "")
8354  {
8355  IMPair = GetVectorPositionsFromInactiveTrackMap(10, TrackVector.at(x).HLoc, TrackVector.at(x).VLoc, FoundFlag);
8356  if(FoundFlag)
8357  {
8358  if((InactiveTrackElementAt(17, IMPair.first).TrackType != Platform) && (InactiveTrackElementAt(18, IMPair.second).TrackType != Platform) &&
8360  {
8361  throw Exception("Track element with ActiveTrackElementName but no plat/named loc at H " + AnsiString(TrackVector.at(x).HLoc) + " & V " +
8362  AnsiString(TrackVector.at(x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
8363  }
8364  if((InactiveTrackElementAt(20, IMPair.first).LocationName != TName) && (InactiveTrackElementAt(21, IMPair.second).LocationName != TName))
8365  {
8366  throw Exception("Track element with ActiveTrackElementName " + TName + " but plat/named loc at H " + AnsiString(TrackVector.at(x).HLoc) +
8367  " & V " + AnsiString(TrackVector.at(x).VLoc) + " has different LocationName in CheckLocationNameMultiMap, caller = " +
8368  AnsiString(Caller));
8369  }
8370  }
8371  else
8372  {
8373  throw Exception("Track element with ActiveTrackElementName but no inactive element at H " + AnsiString(TrackVector.at(x).HLoc) + " & V " +
8374  AnsiString(TrackVector.at(x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
8375  }
8376  }
8377  }
8378  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
8379  {
8380  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
8381  {
8382  SName = InactiveTrackVector.at(x).LocationName;
8383  SNIt = FindNamedElementInLocationNameMultiMap(6, SName, InactiveTrackVector.begin() + x, ErrorString);
8384  if(ErrorString != "")
8385  {
8386  throw Exception(ErrorString + " in CheckLocationNameMultiMap for InactiveTrackVector check, caller = " + AnsiString(Caller));
8387  }
8388  if(SNIt->second != (int)x)
8389  {
8390  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
8391  AnsiString(Caller));
8392  }
8393  }
8394  }
8395  Utilities->CallLogPop(585);
8396 }
8397 
8398 // ---------------------------------------------------------------------------
8399 
8401  AnsiString &ErrorString)
8402 {
8403 /*
8404  Searches the name map to check if the element pointed to by the TTrackVectorIterator has the name
8405  LocationName. If it finds it the pointer TLocationNameMultiMapIterator is returned. If it fails ErrorString
8406  is set to an appropriate text to allow the calling function to report the error. Otherwise it is set to "".
8407 */
8408  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNamedElementInLocationNameMultiMap," + LocationName + "," +
8409  AnsiString(TrackElement->HLoc) + "," + AnsiString(TrackElement->VLoc) + "," + AnsiString(TrackElement->SpeedTag));
8410  ErrorString = "";
8411  bool FoundFlag = false;
8412  TLocationNameMultiMapIterator SNIterator;
8413  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8414 
8415  if(SNRange.first == SNRange.second)
8416  {
8417  ErrorString = "Error, Name " + LocationName + " not found in map";
8418  Utilities->CallLogPop(586);
8419  return SNRange.first;
8420  }
8421  else
8422  {
8423  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
8424  {
8425  if(SNIterator->second < 0)
8426  {
8427  int TVPos = -1 - SNIterator->second;
8428  TTrackVectorIterator TVIt = TrackVector.begin() + TVPos;
8429  if(TVIt == TrackElement)
8430  {
8431  FoundFlag = true;
8432  Utilities->CallLogPop(587);
8433  return SNIterator;
8434  }
8435  }
8436  else
8437  {
8438  int ITVPos = SNIterator->second;
8439  TTrackVectorIterator ITVIt = InactiveTrackVector.begin() + ITVPos;
8440  if(ITVIt == TrackElement)
8441  {
8442  FoundFlag = true;
8443  Utilities->CallLogPop(588);
8444  return SNIterator;
8445  }
8446  }
8447  }
8448  }
8449  if(!FoundFlag)
8450  ErrorString = "Error, Name " + LocationName + " found but not at required element";
8451  Utilities->CallLogPop(589);
8452  return SNIterator;
8453 }
8454 
8455 // ---------------------------------------------------------------------------
8456 
8457 void TTrack::ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
8458 {
8459 /*
8460  Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationNameMultiMapIterator
8461  from whatever it was before. Accepts null entries so that a formerly named element can have the name changed to "".
8462 */
8463  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ChangeLocationNameMultiMapEntry," + NewName);
8464  TLocationNameMultiMapEntry LocationNameEntry;
8465 
8466  LocationNameEntry.first = NewName;
8467  LocationNameEntry.second = SNIterator->second;
8468  LocationNameMultiMap.erase(SNIterator);
8469  LocationNameMultiMap.insert(LocationNameEntry);
8470  Utilities->CallLogPop(590);
8471 }
8472 
8473 // ---------------------------------------------------------------------------
8474 
8476 {
8477 // Takes an adjusted vector position value and returns a pointer to the relevant element. Can be in either vector.
8478  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorIteratorFromNamePosition," + AnsiString(Position));
8479  if(Position < 0) // footcrossing
8480  {
8481  int TruePos = -1 - Position;
8482  // new check at v0.2b
8483  if(TrackElementAt(817, TruePos).TrackType != FootCrossing)
8484  {
8485  throw Exception("Footbridge/underpass error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
8486  }
8487  Utilities->CallLogPop(591);
8488  return (TrackVector.begin() + TruePos);
8489  }
8490  else
8491  {
8492  // new check at v0.2b
8493  if(!(InactiveTrackElementAt(99, Position).FixedNamedLocationElement))
8494  {
8495  throw Exception("Inactive element error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
8496  }
8497  Utilities->CallLogPop(592);
8498  return (InactiveTrackVector.begin() + Position);
8499  }
8500 }
8501 
8502 // ---------------------------------------------------------------------------
8503 
8504 void TTrack::DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
8505 {
8506 /*
8507  After an element has been erased from the inactive track vector, all the later elements are moved down one. This function
8508  decrements the position values for all values above that of the erased element in both InactiveTrack2MultiMap and
8509  LocationNameMultiMap.
8510 */
8511  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInInactiveTrackAndNameMaps," + AnsiString(VecPos));
8512  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
8513  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
8514 
8515  if(!InactiveTrack2MultiMap.empty())
8516  {
8517  for(InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.begin(); InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end();
8518  InactiveTrack2MultiMapIterator++)
8519  {
8520  if(InactiveTrack2MultiMapIterator->second > VecPos)
8521  InactiveTrack2MultiMapIterator->second--;
8522  // can't be == VecPos as that position erased
8523  }
8524  }
8525  if(!LocationNameMultiMap.empty())
8526  {
8527  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
8528  LocationNameMultiMapIterator++)
8529  {
8530  if(LocationNameMultiMapIterator->second < 0)
8531  continue; // deal with TrackVectors separately
8532  if(LocationNameMultiMapIterator->second > (int)VecPos)
8533  LocationNameMultiMapIterator->second--;
8534  }
8535  }
8536  Utilities->CallLogPop(593);
8537 }
8538 
8539 // ---------------------------------------------------------------------------
8540 
8541 void TTrack::DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
8542 {
8543 /*
8544  After an element has been erased from the track vector, all the later elements are moved down one. This function
8545  decrements the position values for all values above that of the erased element in the gap elements, TrackMap and
8546  LocationNameMultiMap.
8547 */
8548  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInGapsAndTrackAndNameMaps," + AnsiString(VecPos));
8549  TTrackMapIterator TrackMapIterator;
8550  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
8551 
8552  if(!TrackMap.empty())
8553  {
8554  for(TrackMapIterator = TrackMap.begin(); TrackMapIterator != TrackMap.end(); TrackMapIterator++)
8555  {
8556  if(TrackMapIterator->second > VecPos)
8557  TrackMapIterator->second--;
8558  // can't be == VecPos as that position erased
8559  }
8560  }
8561  if(!LocationNameMultiMap.empty())
8562  {
8563  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
8564  LocationNameMultiMapIterator++)
8565  {
8566  if(LocationNameMultiMapIterator->second >= 0)
8567  continue; // deal with InactiveTrackVectors separately
8568  // (-1-VecPos) VP 0 1 2 3 4 5 6 7
8569  // Val -1 -2 -3 -4 -5 -6 -7 -8
8570  if(LocationNameMultiMapIterator->second < -(int)(VecPos + 1))
8571  LocationNameMultiMapIterator->second++;
8572  }
8573  }
8574  for(unsigned int x = 0; x < TrackVector.size(); x++)
8575  {
8576  TTrackElement &TkEl = TrackVector.at(x); // no need to check so use this to speed up
8577  if(TkEl.TrackType == GapJump)
8578  {
8579  // position 0 is the gap
8580  if(TkEl.Conn[0] == int(VecPos))
8581  {
8582  TkEl.Conn[0] = -1; // connected to a deleted gap
8583  continue;
8584  }
8585  if(TkEl.Conn[0] > int(VecPos))
8586  TkEl.Conn[0]--;
8587  if(TkEl.Conn[0] > -1) // don't use 'else' here, need to check the value whether changed or not
8588  {
8589  if(TrackElementAt(709, TkEl.Conn[0]).TrackType != GapJump)
8590  TkEl.Conn[0] = -1;
8591  }
8592  }
8593  }
8594  Utilities->CallLogPop(1433);
8595 }
8596 
8597 // ---------------------------------------------------------------------------
8598 
8600 /*
8601  Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector. Called after the
8602  track is linked as many of the vector positions are likely to change - called from RepositionAndMapTrack();
8603  after names are changed in EraseLocationAndActiveTrackElementNames; and after the name changes in EnterLocationName.
8604 */
8605 {
8606  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildLocationNameMultiMap");
8607  LocationNameMultiMap.clear();
8608  TLocationNameMultiMapEntry LocationNameEntry;
8609  TTrackElement TrackElement;
8610 
8611  for(unsigned int TVPos = 0; TVPos < TrackVector.size(); TVPos++)
8612  {
8613  TrackElement = TrackVector.at(TVPos);
8614  if(TrackElement.FixedNamedLocationElement)
8615  {
8616  LocationNameEntry.first = TrackElement.LocationName;
8617  LocationNameEntry.second = -1 - TVPos; // adjusted for footcrossings
8618  LocationNameMultiMap.insert(LocationNameEntry);
8619  }
8620  }
8621 
8622  for(unsigned int ITVPos = 0; ITVPos < InactiveTrackVector.size(); ITVPos++)
8623  {
8624  TrackElement = InactiveTrackVector.at(ITVPos);
8625  if(TrackElement.FixedNamedLocationElement)
8626  {
8627  LocationNameEntry.first = TrackElement.LocationName;
8628  LocationNameEntry.second = ITVPos;
8629  LocationNameMultiMap.insert(LocationNameEntry);
8630  }
8631  }
8632  Utilities->CallLogPop(594);
8633 }
8634 
8635 // ---------------------------------------------------------------------------
8636 
8638  // Return true if there is a named location present in the railway
8639  // ignores lone footcrossings, can't name these on their own & track won't link if there are any
8640 {
8641  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NonFootCrossingNamedLocationExists");
8642  TTrackVectorIterator ITVI;
8643 
8644  if(InactiveTrackVector.empty())
8645  {
8646  Utilities->CallLogPop(1343);
8647  return false;
8648  }
8649  for(ITVI = InactiveTrackVector.begin(); ITVI != InactiveTrackVector.end(); ITVI++)
8650  {
8651  if((ITVI->TrackType == Platform) || (ITVI->TrackType == NamedNonStationLocation) || (ITVI->TrackType == Concourse))
8652  {
8653  Utilities->CallLogPop(1404);
8654  return true;
8655  }
8656  }
8657  Utilities->CallLogPop(1344);
8658  return false;
8659 }
8660 
8661 // ---------------------------------------------------------------------------
8662 
8664 /*
8665  Work through all elements in TrackVector setting all lengths & speed limits to default values - including both tracks for 2-track elements
8666 */
8667 {
8668  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllDefaultLengthsAndSpeedLimits");
8669 // ResetDistanceElements(6);
8670  for(unsigned int x = 0; x < TrackVector.size(); x++)
8671  {
8672  TTrackElement &TE = TrackElementAt(718, x);
8675  if((TE.TrackType == Points) || (TE.TrackType == Crossover) || (TE.TrackType == Bridge))
8676  {
8679  }
8680  }
8681 /* old function
8682  if((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == Crossover) || (TrackVector.at(x).TrackType == Bridge))
8683  {
8684  SetOneDefaultTrackLength(2, TrackVector.at(x), 0);
8685  SetOneDefaultTrackLength(3, TrackVector.at(x), 2);
8686  }
8687  else
8688  {
8689  SetOneDefaultTrackLength(4, TrackVector.at(x), 0);
8690  }
8691  }
8692 */
8693  Utilities->CallLogPop(617);
8694 }
8695 
8696 // ---------------------------------------------------------------------------
8697 
8698 void TTrack::LengthMarker(int Caller, TDisplay *Disp)
8699  // Examine all elements in the TrackVector and if have a valid length mark the relevant track using MarkOneLength.
8700 {
8701  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LengthMarker");
8702  for(unsigned int x = 0; x < TrackVector.size(); x++)
8703  {
8704  TTrackElement TempElement = TrackVector.at(x);
8705  if(TempElement.Length01 > -1)
8706  MarkOneLength(1, TempElement, true, Disp); // need Length01 test in case there are erase elements (but shouldn't be after LinkTrack)
8707  if(TempElement.Length23 > -1)
8708  MarkOneLength(2, TempElement, false, Disp);
8709  }
8710  Disp->Update();
8711  Utilities->CallLogPop(618);
8712 }
8713 
8714 // ---------------------------------------------------------------------------
8715 
8716 void TTrack::MarkOneLength(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp)
8717 /*
8718  Rule: Only marked if different in any way from the default values - length 100m and speed limit 200km/h
8719  First check using IsElementTrackDefaultLength whether the relevant track is already set to the default values, and if so
8720  return as nothing further to do. Otherwise pick up the appropriate bitmap (using the AutoSigRouteGraphicsPtr bitmaps)
8721  using the same technique as in TPrefDirElement::EntryExitNumber() & *TPrefDirElement::GetPrefDirGraphicPtr(), for the relevant
8722  track as indicated by FirstTrack (true for track01 & false for track23).
8723 */
8724 {
8725  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkOneLength," + TrackElement.LogTrack(8) + "," +
8726  AnsiString((short)FirstTrack));
8727  bool LengthDifferent = false, SpeedDifferent = false;
8728 
8729  if(IsElementDefaultLength(1, TrackElement, FirstTrack, LengthDifferent, SpeedDifferent))
8730  {
8731  Utilities->CallLogPop(619);
8732  return;
8733  }
8734 
8735  int EXArray[16][2] =
8736  {{4, 6}, {2, 8}, // horizontal & vertical
8737  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
8738  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
8739  {1, 9}, {3, 7}}; // forward & reverse diagonals
8740 
8741  int Index = -1, BrNum = -1, GrNum = -1, InLink, OutLink;
8742  Graphics::TBitmap *Bitmap;
8743 
8744  if(FirstTrack)
8745  {
8746  InLink = TrackElement.Link[0];
8747  OutLink = TrackElement.Link[1];
8748  }
8749  else
8750  {
8751  InLink = TrackElement.Link[2];
8752  OutLink = TrackElement.Link[3];
8753  }
8754 
8755  for(int x = 0; x < 16; x++)
8756  {
8757  if((InLink == EXArray[x][0] && OutLink == EXArray[x][1]) || (InLink == EXArray[x][1] && OutLink == EXArray[x][0]))
8758  Index = x;
8759  }
8760  if(Index == -1)
8761  {
8762  throw Exception("Error, failed to find Index in TTrack::MarkOneLength");
8763  }
8764 
8765 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
8766  the graphic for each of which is different because of the shape of the overbridge. The basic
8767  entry/exit value is computed above, and this used to select only from elements with that entry/exit
8768  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
8769  int BrEXArray[24][2] = {
8770  {4,6},{2,8},{1,9},{3,7},
8771  {1,9},{3,7},{1,9},{3,7},
8772  {2,8},{4,6},{2,8},{4,6}
8773 */
8774  if(!FirstTrack && (TrackElement.TrackType == Bridge))
8775  {
8776  if(Index == 1)
8777  {
8778  if(TrackElement.SpeedTag == 49)
8779  BrNum = 1 + 16;
8780  else if(TrackElement.SpeedTag == 54)
8781  BrNum = 8 + 16;
8782  else if(TrackElement.SpeedTag == 55)
8783  BrNum = 10 + 16;
8784  }
8785  else if(Index == 0)
8786  {
8787  if(TrackElement.SpeedTag == 48)
8788  BrNum = 0 + 16;
8789  else if(TrackElement.SpeedTag == 58)
8790  BrNum = 11 + 16;
8791  else if(TrackElement.SpeedTag == 59)
8792  BrNum = 9 + 16;
8793  }
8794  else if(Index == 14)
8795  {
8796  if(TrackElement.SpeedTag == 50)
8797  BrNum = 2 + 16;
8798  else if(TrackElement.SpeedTag == 52)
8799  BrNum = 4 + 16;
8800  else if(TrackElement.SpeedTag == 57)
8801  BrNum = 6 + 16;
8802  }
8803  else if(Index == 15)
8804  {
8805  if(TrackElement.SpeedTag == 51)
8806  BrNum = 3 + 16;
8807  else if(TrackElement.SpeedTag == 53)
8808  BrNum = 7 + 16;
8809  else if(TrackElement.SpeedTag == 56)
8810  BrNum = 5 + 16;
8811  }
8812  }
8813 
8814  if(!FirstTrack && (TrackElement.TrackType == Bridge))
8815  GrNum = BrNum;
8816  else
8817  GrNum = Index;
8818 
8819  if(LengthDifferent && SpeedDifferent) // blue - use autosig graphics
8820  {
8821  if(GrNum > 15) // underbridge
8822  {
8823  Bitmap = RailGraphics->BridgeRouteAutoSigsGraphicsPtr[GrNum - 16];
8824  }
8825  else
8826  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[GrNum];
8827 
8828  if(TrackElement.SpeedTag == 64)
8829  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
8830  if(TrackElement.SpeedTag == 65)
8832  if(TrackElement.SpeedTag == 66)
8834  if(TrackElement.SpeedTag == 67)
8836 
8837  if(TrackElement.SpeedTag == 80)
8838  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations to show the dots
8839  if(TrackElement.SpeedTag == 81)
8841  if(TrackElement.SpeedTag == 82)
8843  if(TrackElement.SpeedTag == 83)
8845  if(TrackElement.SpeedTag == 84)
8847  if(TrackElement.SpeedTag == 85)
8849  if(TrackElement.SpeedTag == 86)
8851  if(TrackElement.SpeedTag == 87)
8853 
8854  if(TrackElement.SpeedTag == 129)
8855  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
8856  if(TrackElement.SpeedTag == 130)
8858  }
8859 
8860  else if(LengthDifferent && !SpeedDifferent) // green - use pref sig graphics
8861  {
8862  if(GrNum > 15) // underbridge
8863  {
8864  Bitmap = RailGraphics->BridgeSigRouteGraphicsPtr[GrNum - 16];
8865  }
8866  else
8867  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[GrNum];
8868 
8869  if(TrackElement.SpeedTag == 64)
8870  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
8871  if(TrackElement.SpeedTag == 65)
8872  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[17];
8873  if(TrackElement.SpeedTag == 66)
8874  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[18];
8875  if(TrackElement.SpeedTag == 67)
8876  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[19];
8877 
8878  if(TrackElement.SpeedTag == 80)
8879  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
8880  if(TrackElement.SpeedTag == 81)
8881  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[21];
8882  if(TrackElement.SpeedTag == 82)
8883  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[22];
8884  if(TrackElement.SpeedTag == 83)
8885  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[23];
8886  if(TrackElement.SpeedTag == 84)
8887  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[24];
8888  if(TrackElement.SpeedTag == 85)
8889  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[25];
8890  if(TrackElement.SpeedTag == 86)
8891  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[26];
8892  if(TrackElement.SpeedTag == 87)
8893  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[27];
8894 
8895  if(TrackElement.SpeedTag == 129)
8896  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
8897  if(TrackElement.SpeedTag == 130)
8898  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[29];
8899  }
8900 
8901  else // SpeedDifferent only: red - use non sig graphics
8902  {
8903  if(GrNum > 15) // underbridge
8904  {
8905  Bitmap = RailGraphics->BridgeNonSigRouteGraphicsPtr[GrNum - 16];
8906  }
8907  else
8908  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[GrNum];
8909 
8910  if(TrackElement.SpeedTag == 64)
8911  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
8912  if(TrackElement.SpeedTag == 65)
8914  if(TrackElement.SpeedTag == 66)
8916  if(TrackElement.SpeedTag == 67)
8918 
8919  if(TrackElement.SpeedTag == 80)
8920  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
8921  if(TrackElement.SpeedTag == 81)
8923  if(TrackElement.SpeedTag == 82)
8925  if(TrackElement.SpeedTag == 83)
8927  if(TrackElement.SpeedTag == 84)
8929  if(TrackElement.SpeedTag == 85)
8931  if(TrackElement.SpeedTag == 86)
8933  if(TrackElement.SpeedTag == 87)
8935 
8936  if(TrackElement.SpeedTag == 129)
8937  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
8938  if(TrackElement.SpeedTag == 130)
8940  }
8941 
8942  Disp->PlotOutput(67, TrackElement.HLoc * 16, TrackElement.VLoc * 16, Bitmap);
8943  Utilities->CallLogPop(620);
8944 }
8945 
8946 // ---------------------------------------------------------------------------
8947 
8948 bool TTrack::IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
8949 /* FirstTrack = LinkPos's 0 & 1
8950  Examine track within TrackElement & check whether it has the default length and speed limit, return true if so
8951 */
8952 {
8953  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementTrackDefaultLength," + TrackElement.LogTrack(10) + "," +
8954  AnsiString((short)FirstTrack));
8955  LengthDifferent = false;
8956  SpeedDifferent = false;
8957  if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && FirstTrack)
8958  {
8959  if(TrackElement.Length01 != DefaultTrackLength)
8960  {
8961  LengthDifferent = true;
8962  }
8963  if(TrackElement.SpeedLimit01 != DefaultTrackSpeedLimit)
8964  {
8965  SpeedDifferent = true;
8966  }
8967  if(LengthDifferent || SpeedDifferent)
8968  {
8969  Utilities->CallLogPop(625);
8970  return false;
8971  }
8972  Utilities->CallLogPop(626);
8973  return true;
8974  }
8975 
8976  else if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && !FirstTrack)
8977  {
8978  if(TrackElement.Length23 != DefaultTrackLength)
8979  {
8980  LengthDifferent = true;
8981  }
8982  if(TrackElement.SpeedLimit23 != DefaultTrackSpeedLimit)
8983  {
8984  SpeedDifferent = true;
8985  }
8986  if(LengthDifferent || SpeedDifferent)
8987  {
8988  Utilities->CallLogPop(627);
8989  return false;
8990  }
8991  Utilities->CallLogPop(628);
8992  return true;
8993  }
8994 
8995  else // any other 1 track element, including platforms being present
8996  {
8997  if(TrackElement.Length01 != DefaultTrackLength)
8998  {
8999  LengthDifferent = true;
9000  }
9001  if(TrackElement.SpeedLimit01 != DefaultTrackSpeedLimit)
9002  {
9003  SpeedDifferent = true;
9004  }
9005  if(LengthDifferent || SpeedDifferent)
9006  {
9007  Utilities->CallLogPop(629);
9008  return false;
9009  }
9010  Utilities->CallLogPop(630);
9011  return true;
9012  }
9013 }
9014 
9015 // ---------------------------------------------------------------------------
9016 
9017 bool TTrack::IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
9018  // Check whether there is a platform or NamedNonStationLocation present at HLoc & VLoc, return true if so
9019 {
9020  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPlatformOrNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
9021  AnsiString(VLoc));
9022  bool FoundFlag;
9023  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(11, HLoc, VLoc, FoundFlag);
9024 
9025  if(!FoundFlag)
9026  {
9027  Utilities->CallLogPop(633);
9028  return false;
9029  }
9030  if((InactiveTrackElementAt(42, IMPair.first).TrackType == Platform) || (InactiveTrackElementAt(91, IMPair.first).TrackType == NamedNonStationLocation))
9031  {
9032  Utilities->CallLogPop(634);
9033  return true; // only need to check first since if second is a platform the the first must be too
9034  }
9035  else
9036  {
9037  Utilities->CallLogPop(635);
9038  return false;
9039  }
9040 }
9041 
9042 // ---------------------------------------------------------------------------
9043 
9044 bool TTrack::IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
9045  // Check whether there is a NamedNonStationLocation present at HLoc & VLoc, return true if so
9046 {
9047  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
9048  AnsiString(VLoc));
9049  bool FoundFlag;
9050  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(12, HLoc, VLoc, FoundFlag);
9051 
9052  if(!FoundFlag)
9053  {
9054  Utilities->CallLogPop(636);
9055  return false;
9056  }
9058  {
9059  Utilities->CallLogPop(637);
9060  return true; // only need to check first since only one used for NamedNonStationLocations
9061  }
9062  else
9063  {
9064  Utilities->CallLogPop(638);
9065  return false;
9066  }
9067 }
9068 
9069 // ---------------------------------------------------------------------------
9070 
9072 /* Called when trying to link track and when a name changed when track already linked. Examines all track elements that
9073  have ActiveTrackElementName set, sums the number of consecutive elements with the same name, and sets the EntryLink values for
9074  the front of train stop points for each direction.
9075  For stations (not non-station named locations) of length n, where n > 1, stop element is [floor((n+1)/2) + 1] from each
9076  end (unless buffers at one or both ends in which case stop points are the end elements).
9077  Note that for a single element the stop point is the element itself (formula doesn't apply).
9078  During the function the StationEntryStopLink values are set to 5 if not used, so no need to keep
9079  repeating the procedure for every element. At the end all unused values are returned to -1.
9080  For NamedNonStationLocations the stop points are at the end elements to allow trains to stack up.
9081 */
9082 {
9083  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetStationEntryStopLinkPosses");
9084  TTrackElement TempElement, StartElement;
9085  AnsiString TempName;
9086  int VecPos, StartVecPos, Count, EntryPos, StartEntryPos, ForwardNumber, ReverseNumber;
9087  bool ForwardSet, ReverseSet;
9088 
9089  for(unsigned int x = 0; x < TrackVector.size(); x++)
9090  {
9091  TrackVector.at(x).StationEntryStopLinkPos1 = -1;
9092  TrackVector.at(x).StationEntryStopLinkPos2 = -1;
9093  }
9094  for(unsigned int x = 0; x < TrackVector.size(); x++)
9095  {
9096  ForwardSet = false;
9097  ReverseSet = false;
9098  TempElement = TrackVector.at(x);
9099  VecPos = x;
9100  if((TempElement.ActiveTrackElementName != "") && (TempElement.StationEntryStopLinkPos1 == -1))
9101  // 2nd condition incl so don't re-examine elements with stop links set to 5
9102  {
9103  TempName = TempElement.ActiveTrackElementName;
9104  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(44, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
9105  (TrackElementAt(45, TempElement.Conn[1]).ActiveTrackElementName == TempName))
9106  // an element linked at both ends where both links are also named elements
9107  // only Conn[0] & [1] relevant for ActiveTrackElementName elements (only 2-track named element is points, and only straight track relevant & this has 0 & 1 as entry/exit positions)
9108  {
9109  continue; // looking for an end element so skip this one
9110  }
9111  else // reached one end
9112  {
9113  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(46, TempElement.Conn[0]).ActiveTrackElementName != TempName) &&
9114  (TrackElementAt(47, TempElement.Conn[1]).ActiveTrackElementName != TempName))
9115  // single named element linked at both ends
9116  {
9117  TrackElementAt(48, VecPos).StationEntryStopLinkPos1 = 0;
9118  TrackElementAt(49, VecPos).StationEntryStopLinkPos2 = 1;
9119  continue;
9120  }
9121  else if((TempElement.TrackType == Buffers) && (TrackElementAt(618, TempElement.Conn[1]).ActiveTrackElementName != TempName))
9122  // single named buffer element (LinkPos 1 is the non-buffer end)
9123  {
9124  TrackElementAt(619, VecPos).StationEntryStopLinkPos1 = 0;
9125  TrackElementAt(620, VecPos).StationEntryStopLinkPos2 = 1;
9126  continue;
9127  }
9128  else
9129  // Note: only interested in connection positions 0 & 1 since all named elements are single track except points,
9130  // and platforms always on straight (conns 0 & 1) section of points
9131  {
9132  for(int y = 0; y < 2; y++)
9133  {
9134  int Dir = y; // Dir is the ExitPos of the element, towards the rest of the named elements
9135  // check for buffers at both ends - no need, function below now covers buffers at one & both ends
9136 /* TTrackElement Temp1 = TempElement;
9137  ***********New section, compiles but not checked - does bit below need to be else if?
9138  if((Temp1.TrackType == Buffers) && (Temp1.GetConfig(Dir) != End))
9139  {
9140  //search along Dir direction until find other end, skip if Dir facing buffer end
9141  int NewDir = Dir;
9142  int NewVecPos;
9143  while((Temp1.Conn[NewDir] > -1) && (TrackElementAt(598, Temp1.Conn[NewDir]).ActiveTrackElementName == TempName))
9144  {
9145  NewVecPos = Temp1.Conn[NewDir];
9146  NewDir = Track->GetNonPointsOppositeLinkPos(Temp1.ConnLinkPos[NewDir]);
9147  Temp1 = TrackElementAt(601, NewVecPos);
9148  }
9149  if((Temp1.Conn[NewDir] == -1) && (Temp1.TrackType == Buffers))
9150  {
9151  TrackElementAt(599, VecPos).StationEntryStopLinkPos1 = Dir;//EntryPos for train coming from other end is Dir
9152  TrackElementAt(600, NewVecPos).StationEntryStopLinkPos2 = 1 - NewDir;//For train moving in same direction as search direction its EntryPos == 1 - NewDir since NewDir is the ExitPos
9153  }
9154  }
9155  ***************
9156 */
9157  // end may be linked at both ends but only one link named, or buffer with linked element named
9158  // if a buffer then the named linkpos has to be 1
9159  // already dealt with all types of single element so at least 2 linked named element
9160  if(((TempElement.Conn[Dir] > -1) && (TempElement.Conn[1 - Dir] > -1) && (TrackElementAt(50,
9161  TempElement.Conn[1 - Dir]).ActiveTrackElementName != TempName)) || ((TempElement.TrackType == Buffers) && (Dir == 1)))
9162  {
9163  StartElement = TempElement;
9164  StartVecPos = VecPos;
9165  TrackElementAt(51, VecPos).StationEntryStopLinkPos1 = 5; // set to 5 to stop re-examination in later searches, all set back at end
9166  TrackElementAt(52, VecPos).StationEntryStopLinkPos2 = 5;
9167  EntryPos = 1 - Dir;
9168  StartEntryPos = 1 - Dir;
9169  Count = 1;
9170  // work along named elements until find the other end
9171  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(53,
9172  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName))
9173  // at end of 'while' Count = length (in elements) of platform/nonstationloc, VecPos = vector number of far end
9174  // which is the last named element that is track-linked to the rest of the location, it may be a buffer
9175  // all stop link pos's are set to 5
9176  {
9177  VecPos = TempElement.Conn[1 - EntryPos];
9178  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
9179  TempElement = TrackElementAt(54, TempElement.Conn[1 - EntryPos]);
9180  EntryPos = TempEntryPos;
9181  Count++;
9182  TrackElementAt(55, VecPos).StationEntryStopLinkPos1 = 5;
9183  TrackElementAt(56, VecPos).StationEntryStopLinkPos2 = 5;
9184  }
9185  // here when reached other end, maybe buffers, continuation or last named linked element
9186  if(TrackElementAt(57, VecPos).TrackType == Buffers)
9187  // terminal station, set end elements as stop elements
9188  {
9189  TrackElementAt(58, VecPos).StationEntryStopLinkPos1 = EntryPos;
9190  TrackElementAt(59, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos; // for train leaving
9191  continue;
9192  }
9193  if(TrackElementAt(60, StartVecPos).TrackType == Buffers) // best not to use 'else if' as both ends could be buffers!
9194  // terminal station, set end elements as stop elements
9195  {
9196  TrackElementAt(61, VecPos).StationEntryStopLinkPos1 = EntryPos;
9197  TrackElementAt(62, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
9198  continue;
9199  }
9200  if(IsNamedNonStationLocationPresent(1, TrackElementAt(63, StartVecPos).HLoc, TrackElementAt(64, StartVecPos).VLoc))
9201  // NonStationLocation so set end elements as stop elements
9202  {
9203  TrackElementAt(65, VecPos).StationEntryStopLinkPos1 = EntryPos;
9204  TrackElementAt(66, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
9205  continue;
9206  }
9207  // now Count == length of platform, can calculate StationEntryStopLinkPos values and the elements to which they apply
9208  ForwardNumber = ((Count + 1) / 2) + 1;
9209  ReverseNumber = (Count - ForwardNumber) + 1;
9210  Count = 1; // starting value
9211  EntryPos = 1 - Dir;
9212  TempElement = StartElement;
9213  VecPos = StartVecPos;
9214  if(Count == ForwardNumber)
9215  {
9216  TrackElementAt(67, VecPos).StationEntryStopLinkPos1 = EntryPos;
9217  ForwardSet = true;
9218  }
9219  if(Count == ReverseNumber) // don't use 'else' as may both be at same element
9220  {
9221  TrackElementAt(68, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
9222  ReverseSet = true;
9223  }
9224  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(69,
9225  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName) && (!ForwardSet || !ReverseSet))
9226  {
9227  VecPos = TempElement.Conn[1 - EntryPos];
9228  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
9229  TempElement = TrackElementAt(70, TempElement.Conn[1 - EntryPos]);
9230  EntryPos = TempEntryPos;
9231  Count++;
9232  if(Count == ForwardNumber)
9233  {
9234  TrackElementAt(71, VecPos).StationEntryStopLinkPos1 = EntryPos;
9235  ForwardSet = true;
9236  }
9237  if(Count == ReverseNumber)
9238  {
9239  TrackElementAt(72, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
9240  ReverseSet = true;
9241  }
9242  }
9243  }
9244  }
9245  }
9246  }
9247  }
9248  }
9249  for(unsigned int x = 0; x < TrackVector.size(); x++)
9250  {
9251  if(TrackVector.at(x).StationEntryStopLinkPos1 == 5)
9252  {
9253  TrackVector.at(x).StationEntryStopLinkPos1 = -1;
9254  }
9255  if(TrackVector.at(x).StationEntryStopLinkPos2 == 5)
9256  {
9257  TrackVector.at(x).StationEntryStopLinkPos2 = -1;
9258  }
9259  }
9260  Utilities->CallLogPop(639);
9261 }
9262 
9263 // ---------------------------------------------------------------------------
9264 
9265 void TTrack::PlotSmallRailway(int Caller, TDisplay *Disp)
9266 {
9267  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRailway");
9268  TTrackElement Next;
9269 
9271  while(ReturnNextInactiveTrackElement(1, Next))
9272  {
9273  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
9274  {
9275  if(((Next.TrackType == Platform) || (Next.TrackType == Concourse) || (Next.TrackType == NamedNonStationLocation)) && (Next.LocationName == ""))
9276  // need striped graphics
9277  {
9278  if(Next.SpeedTag == 76)
9279  Disp->PlotSmallOutput(11, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm76striped);
9280  else if(Next.SpeedTag == 77)
9281  Disp->PlotSmallOutput(12, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm77striped);
9282  else if(Next.SpeedTag == 78)
9283  Disp->PlotSmallOutput(13, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm78striped);
9284  else if(Next.SpeedTag == 79)
9285  Disp->PlotSmallOutput(14, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm79striped);
9286  else if(Next.SpeedTag == 96)
9287  Disp->PlotSmallOutput(15, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm96striped);
9288  else if(Next.SpeedTag == 131)
9289  Disp->PlotSmallOutput(16, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm131striped);
9290  }
9291  else
9292  Disp->PlotSmallOutput(17, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
9293  }
9294  }
9295 
9296  NextTrackElementPtr = TrackVector.begin();
9297  while(ReturnNextTrackElement(1, Next))
9298  {
9299  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
9300  {
9301  if((Next.TrackType == FootCrossing) && (Next.LocationName == "")) // need striped graphics, use sm129 & 130 for 145 & 146
9302  {
9303  if((Next.SpeedTag == 129) || (Next.SpeedTag == 145))
9304  Disp->PlotSmallOutput(18, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm129striped);
9305  else if((Next.SpeedTag == 130) || (Next.SpeedTag == 146))
9306  Disp->PlotSmallOutput(19, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm130striped);
9307  }
9308  else
9309  Disp->PlotSmallOutput(20, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
9310  }
9311  }
9312  Disp->Update();
9313  Utilities->CallLogPop(640);
9314 }
9315 
9316 // ---------------------------------------------------------------------------
9317 
9318 void TTrack::PlotSmallRedGap(int Caller)
9319 {
9320  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRedGap");
9322  Utilities->CallLogPop(1346);
9323 }
9324 
9325 // ---------------------------------------------------------------------------
9326 
9327 void TTrack::TrackClear(int Caller)
9328 {
9329  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackClear");
9330  TrackVector.clear();
9331  InactiveTrackVector.clear();
9332  TrackMap.clear();
9334  if(TextHandler->TextVector.size() == 0)
9335  {
9336  Display->DisplayOffsetH = 0;
9337  Display->DisplayOffsetV = 0;
9344  HLocMin = 2000000000;
9345  HLocMax = -2000000000;
9346  VLocMin = 2000000000;
9347  VLocMax = -2000000000;
9348  }
9349  else
9350  CalcHLocMinEtc(4);
9351  Utilities->CallLogPop(1347);
9352 }
9353 
9354 // ---------------------------------------------------------------------------
9355 
9356 void TTrack::CalcHLocMinEtc(int Caller)
9357 {
9358  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcHLocMinEtc");
9359  HLocMin = 2000000000;
9360  VLocMin = 2000000000;
9361  HLocMax = -2000000000;
9362  VLocMax = -2000000000;
9363  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
9364  {
9365  if(TrackVector.at(x).SpeedTag == 0)
9366  continue; // skip erase elements or would interfere with Min & Max values
9367  if(TrackVector.at(x).HLoc - 1 < HLocMin)
9368  HLocMin = TrackVector.at(x).HLoc - 1; // add one all round
9369  if(TrackVector.at(x).HLoc + 1 > HLocMax)
9370  HLocMax = TrackVector.at(x).HLoc + 1;
9371  if(TrackVector.at(x).VLoc - 1 < VLocMin)
9372  VLocMin = TrackVector.at(x).VLoc - 1;
9373  if(TrackVector.at(x).VLoc + 1 > VLocMax)
9374  VLocMax = TrackVector.at(x).VLoc + 1;
9375  }
9376  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++) // check all elements in turn
9377  {
9378  if(InactiveTrackVector.at(x).SpeedTag == 0)
9379  continue; // shouldn't be any inactive erase elements but include anyway
9380  if(InactiveTrackVector.at(x).HLoc - 1 < HLocMin)
9381  HLocMin = InactiveTrackVector.at(x).HLoc - 1; // add one all round
9382  if(InactiveTrackVector.at(x).HLoc + 1 > HLocMax)
9383  HLocMax = InactiveTrackVector.at(x).HLoc + 1;
9384  if(InactiveTrackVector.at(x).VLoc - 1 < VLocMin)
9385  VLocMin = InactiveTrackVector.at(x).VLoc - 1;
9386  if(InactiveTrackVector.at(x).VLoc + 1 > VLocMax)
9387  VLocMax = InactiveTrackVector.at(x).VLoc + 1;
9388  }
9389  for(unsigned int x = 0; x < TextHandler->TextVectorSize(10); x++) // check all elements in turn
9390  {
9391 /* Removed at v2.2.0: It isn't needed because null names aren't entered into vector, and in any case if were then
9392  will fail as x will exceed the maximum value
9393  if(TextHandler->TextPtrAt(, x)->TextString == "")
9394  {
9395  TextHandler->TextErase(, TextHandler->TextPtrAt(35, x)->HPos, TextHandler->TextPtrAt(36, x)->VPos);
9396  }
9397 */
9398  int TextH = TextHandler->TextPtrAt(0, x)->HPos, TextV = TextHandler->TextPtrAt(1, x)->VPos;
9399  if((TextH / 16) - 1 < HLocMin)
9400  HLocMin = (TextH / 16) - 1; // integer division will truncate so subtract 1 to ensure include the start
9401  if((TextH / 16) + 1 > HLocMax)
9402  HLocMax = (TextH / 16) + 1; // integer division will truncate so add 1 to ensure include the start
9403  if((TextV / 16) - 1 < VLocMin)
9404  VLocMin = (TextV / 16) - 1;
9405  if((TextV / 16) + 1 > VLocMax)
9406  VLocMax = (TextV / 16) + 1;
9407  }
9408  for(unsigned int x = 0; x < UserGraphicVector.size(); x++) // added at v2.4.0
9409  {
9410  if((UserGraphicVectorAt(5, x).HPos / 16) - 1 < HLocMin)
9411  HLocMin = (UserGraphicVectorAt(6, x).HPos / 16) - 1; // add one all round
9412  if(((UserGraphicVectorAt(7, x).HPos + UserGraphicVectorAt(8, x).Width) / 16) + 1 > HLocMax)
9413  HLocMax = ((UserGraphicVectorAt(9, x).HPos + UserGraphicVectorAt(10, x).Width) / 16) + 1;
9414  if((UserGraphicVectorAt(11, x).VPos / 16) - 1 < VLocMin)
9415  VLocMin = (UserGraphicVectorAt(12, x).VPos / 16) - 1;
9416  if(((UserGraphicVectorAt(13, x).VPos + UserGraphicVectorAt(14, x).Height) / 16) + 1 > VLocMax)
9417  VLocMax = ((UserGraphicVectorAt(15, x).VPos + UserGraphicVectorAt(16, x).Height) / 16) + 1;
9418  }
9419 
9420  Utilities->CallLogPop(641);
9421 }
9422 
9423 // ---------------------------------------------------------------------------
9424 
9425 void TTrack::UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos,
9426  bool &UserGraphicFoundFlag)
9427 {
9428  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicMove," + AnsiString(HPosInput) + "," + AnsiString(VPosInput));
9429  TUserGraphicVector::iterator UserGraphicPtr;
9430 
9431  UserGraphicFoundFlag = false;
9432  if(!UserGraphicVector.empty())
9433  {
9434  int x = UserGraphicVector.size();
9435  for(UserGraphicPtr = (UserGraphicVector.end() - 1); UserGraphicPtr >= UserGraphicVector.begin(); UserGraphicPtr--)
9436  {
9437  x--;
9438  if((HPosInput >= (*UserGraphicPtr).HPos) && (HPosInput < ((*UserGraphicPtr).HPos + (*UserGraphicPtr).Width)) && (VPosInput >=
9439  (*UserGraphicPtr).VPos) && (VPosInput < ((*UserGraphicPtr).VPos + (*UserGraphicPtr).Height)))
9440  {
9441  UserGraphicItem = x;
9442  UserGraphicMoveHPos = (*UserGraphicPtr).HPos;
9443  UserGraphicMoveVPos = (*UserGraphicPtr).VPos;
9444  UserGraphicFoundFlag = true;
9445  Utilities->CallLogPop(2177);
9446  return;
9447  } // if ....
9448  } // for UserGraphicPtr...
9449  } // if !UserGraphicVector...
9450  Utilities->CallLogPop(2197);
9451 }
9452 
9453 // ---------------------------------------------------------------------------
9454 
9456 {
9457  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RetrieveStripedNamedLocationGraphicsWhereRelevant," +
9458  TrackElement.LogTrack(11));
9459  Graphics::TBitmap *GraphicOutput = RailGraphics->bmTransparentBgnd; // default value
9460  int SpeedTag = TrackElement.SpeedTag;
9461 
9462  if(SpeedTag < 1)
9463  {
9464  throw Exception("Error - SpeedTag value " + AnsiString(SpeedTag) + " in RetrieveStripedNamedLocationGraphicsWhereRelevant");
9465  }
9466  switch(SpeedTag)
9467  {
9468  case 76: // t platform
9469  GraphicOutput = RailGraphics->gl76Striped;
9470  break;
9471 
9472  case 77: // h platform
9473  GraphicOutput = RailGraphics->bm77Striped;
9474  break;
9475 
9476  case 78: // v platform
9477  GraphicOutput = RailGraphics->bm78Striped;
9478  break;
9479 
9480  case 79: // r platform
9481  GraphicOutput = RailGraphics->gl79Striped;
9482  break;
9483 
9484  case 96: // concourse
9485  GraphicOutput = RailGraphics->ConcourseStriped;
9486  break;
9487 
9488  case 129: // v footbridge
9489  GraphicOutput = RailGraphics->gl129Striped;
9490  break;
9491 
9492  case 130: // h footbridge
9493  GraphicOutput = RailGraphics->gl130Striped;
9494  break;
9495 
9496  case 131: // non-station named loc
9497  GraphicOutput = RailGraphics->bmNameStriped;
9498  break;
9499 
9500  case 145: // v u'pass
9501  GraphicOutput = RailGraphics->gl145Striped;
9502  break;
9503 
9504  case 146: // h u'pass
9505  GraphicOutput = RailGraphics->gl146Striped;
9506  break;
9507 
9508  default:
9509  GraphicOutput = TrackElement.GraphicPtr;
9510  break;
9511  }
9512  Utilities->CallLogPop(642);
9513  return GraphicOutput;
9514 }
9515 
9516 // ---------------------------------------------------------------------------
9517 
9519 {
9520  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementAt," + AnsiString(At));
9521  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
9522  {
9523  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in TrackElementAt");
9524  }
9525  Utilities->CallLogPop(643);
9526  return TrackVector.at(At);
9527 }
9528 
9529 // ---------------------------------------------------------------------------
9530 
9532 {
9533  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementAt," + AnsiString(At));
9534  if((At < 0) || ((unsigned int)At >= InactiveTrackVector.size()))
9535  {
9536  throw Exception("Out of Range Error, vector size: " + AnsiString(InactiveTrackVector.size()) + ", At: " + AnsiString(At) +
9537  " in InactiveTrackElementAt");
9538  }
9539  Utilities->CallLogPop(644);
9540  return InactiveTrackVector.at(At);
9541 }
9542 
9543 // ---------------------------------------------------------------------------
9544 
9545 bool TTrack::BlankElementAt(int Caller, int At) const
9546 {
9547  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BlankElementAt," + AnsiString(At));
9548  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
9549  {
9550  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in BlankElementAt");
9551  }
9552  if(TrackVector.at(At).SpeedTag == 0)
9553  {
9554  Utilities->CallLogPop(645);
9555  return true;
9556  }
9557  else
9558  {
9559  Utilities->CallLogPop(646);
9560  return false;
9561  }
9562 }
9563 
9564 // ---------------------------------------------------------------------------
9565 
9566 bool TTrack::OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
9567 /* Check sufficient elements with same ActiveTrackElementName linked together without any trailing point links to allow a train split.
9568  Only one length is needed to return true, but this doesn't mean that all platforms at the location are long enough. When a
9569  split is required a specific check is made using ThisNamedLocationLongEnoughForSplit.
9570  Need at least two linked ActiveTrackElementNames, with connected elements at each end, which may or may not be ActiveTrackElementNames,
9571  and no connections via point trailing links. Note that these conditions exclude opposed buffers since these not linked.
9572 */
9573 {
9574  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationLongEnoughForSplit," + LocationName);
9575  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
9576  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
9577  TLocationNameMultiMapIterator SNIterator;
9578  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9579 
9580  if(SNRange.first == SNRange.second)
9581  {
9582  Utilities->CallLogPop(972);
9583  return false; // should have been caught earlier but include for completeness
9584  }
9585  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9586  {
9587  if(SNIterator->second < 0)
9588  continue; // exclude footcrossings
9589  InactiveElement = InactiveTrackElementAt(47, SNIterator->second);
9590  if(InactiveElement.TrackType == Concourse)
9591  continue; // only interested in locations where ActiveTrackElementName may be set
9592  THVPair HVPair;
9593  HVPair.first = InactiveElement.HLoc;
9594  HVPair.second = InactiveElement.VLoc;
9595  if(TrackMap.find(HVPair) == TrackMap.end())
9596  {
9597  throw Exception
9598  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneNamedLocationLongEnoughForSplit (1)");
9599  }
9600  int TVPos = TrackMap.find(HVPair)->second;
9601  FirstNamedElement = TrackElementAt(560, TVPos);
9602  // first check linked on both sides, skip the check if not
9603  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
9604  {
9605  continue;
9606  }
9607  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
9608  // ActiveTrackElementNames are points and excluding trailing connections for points
9609  FirstNamedExitPos = 0;
9610  {
9611  SecondNamedElement = TrackElementAt(561, FirstNamedElement.Conn[FirstNamedExitPos]);
9612  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
9613  FirstNamedLinkedElement = TrackElementAt(562, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
9614  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
9615  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
9616  {
9617  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
9618  {
9619  SecondNamedLinkedElement = TrackElementAt(563, SecondNamedElement.Conn[SecondNamedExitPos]);
9620  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
9621  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
9622  // success, now check FirstNamedElement link not trailing points & if so all OK
9623  {
9624  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
9625  {
9626  Utilities->CallLogPop(1002);
9627  return true;
9628  }
9629  }
9630  }
9631  }
9632  }
9633  // failed, try link 1
9634  FirstNamedExitPos = 1;
9635  {
9636  SecondNamedElement = TrackElementAt(564, FirstNamedElement.Conn[FirstNamedExitPos]);
9637  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
9638  FirstNamedLinkedElement = TrackElementAt(565, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
9639  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
9640  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
9641  {
9642  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
9643  {
9644  SecondNamedLinkedElement = TrackElementAt(566, SecondNamedElement.Conn[SecondNamedExitPos]);
9645  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
9646  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
9647  // success, now check FirstNamedElement link not trailing points & if so all OK
9648  {
9649  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
9650  {
9651  Utilities->CallLogPop(1003);
9652  return true;
9653  }
9654  }
9655  }
9656  }
9657  }}
9658  Utilities->CallLogPop(1004);
9659  return false;
9660 }
9661 
9662 // ---------------------------------------------------------------------------
9663 bool TTrack::ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos,
9664  int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
9665  // for success need two linked named location elements, so that one element of each train can be at the location
9666  // FirstNamedElementPos is the input vector position and the first (if successful) of the two linked named location elements,
9667  // the second is SecondNamedElementPos, and the two linked elements are FirstNamedLinkedElementPos and SecondNamedLinkedElementPos.
9668  // the two trains will occupy these 4 elements
9669  // All are track vector positions, all but the input being references and set within the function.
9670 {
9671 /* Check sufficient elements (including TrackvectorPosition) with same ActiveTrackElementName linked together without any trailing point
9672  links and including the element FirstNamedElementPos to allow a train split. Need at least two linked ActiveTrackElementNames, with
9673  connected elements at each end, which may or may not be ActiveTrackElementNames, and no connections via point trailing links. Note that
9674  these conditions exclude opposed buffers since these not linked. Return the two train positions and exit positions for use in train
9675  splitting.
9676 */
9677  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ThisNamedLocationLongEnoughForSplit," + LocationName +
9678  AnsiString(FirstNamedElementPos));
9679  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
9680  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
9681 
9682  SecondNamedElementPos = -1;
9683  FirstNamedLinkedElementPos = -1;
9684  SecondNamedLinkedElementPos = -1;
9685  TLocationNameMultiMapIterator SNIterator;
9686  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9687 
9688  if(SNRange.first == SNRange.second) // i.e. location name not in map
9689  {
9690  Utilities->CallLogPop(1005);
9691  return false; // should have been caught earlier but include for completeness
9692  }
9693  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9694  {
9695  if(SNIterator->second < 0)
9696  continue; // exclude footcrossings
9697  InactiveElement = InactiveTrackElementAt(69, SNIterator->second);
9698  if(InactiveElement.TrackType == Concourse)
9699  continue; // only interested in locations where ActiveTrackElementName may be set
9700  THVPair HVPair;
9701  HVPair.first = InactiveElement.HLoc;
9702  HVPair.second = InactiveElement.VLoc;
9703  if(TrackMap.find(HVPair) == TrackMap.end())
9704  {
9705  if(InactiveElement.TrackType == NamedNonStationLocation) // added at v2.2.0 to correct the error Xeon reported on 14/07/18.
9706  // If there is a NamedNonStationLocation without an associated active track element (effectively a non-station concourse)
9707  // then it won't be found in TrackMap but it's still legitimate.
9708  {
9709  continue;
9710  }
9711  else // for anything else throw the error
9712  {
9713  throw Exception
9714  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in ThisNamedLocationLongEnoughForSplit (2)"
9715  );
9716  }
9717  }
9718  int TVPos = TrackMap.find(HVPair)->second;
9719  if(TVPos != FirstNamedElementPos)
9720  continue; // looking for an exact match
9721  FirstNamedElement = TrackElementAt(567, TVPos);
9722  // first check linked on both sides, skip the check if not
9723  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
9724  {
9725  continue;
9726  }
9727  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
9728  // ActiveTrackElementNames are points and excluding trailing connections for points
9729  FirstNamedExitPos = 0;
9730  {
9731  SecondNamedElement = TrackElementAt(568, FirstNamedElement.Conn[FirstNamedExitPos]);
9732  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
9733  FirstNamedLinkedElement = TrackElementAt(569, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
9734  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
9735  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
9736  {
9737  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
9738  {
9739  SecondNamedLinkedElement = TrackElementAt(570, SecondNamedElement.Conn[SecondNamedExitPos]);
9740  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
9741  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
9742  // success, now check FirstNamedElement link not trailing points & if so all OK
9743  {
9744  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
9745  {
9746  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
9747  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
9748  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
9749  Utilities->CallLogPop(1006);
9750  return true;
9751  }
9752  }
9753  }
9754  }
9755  }
9756  // failed, try link 1
9757  FirstNamedExitPos = 1;
9758  {
9759  SecondNamedElement = TrackElementAt(571, FirstNamedElement.Conn[FirstNamedExitPos]);
9760  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
9761  FirstNamedLinkedElement = TrackElementAt(572, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
9762  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
9763  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
9764  {
9765  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
9766  {
9767  SecondNamedLinkedElement = TrackElementAt(573, SecondNamedElement.Conn[SecondNamedExitPos]);
9768  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
9769  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
9770  // success, now check FirstNamedElement link not trailing points & if so all OK
9771  {
9772  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
9773  {
9774  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
9775  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
9776  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
9777  Utilities->CallLogPop(1007);
9778  return true;
9779  }
9780  }
9781  }
9782  }
9783  }}
9784  Utilities->CallLogPop(1008);
9785  return false;
9786 }
9787 
9788 // ---------------------------------------------------------------------------
9789 
9790 bool TTrack::OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
9791 {
9792  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationElementAtLocation," + LocationName);
9793  TLocationNameMultiMapIterator SNIterator;
9794  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9795 
9796  if(SNRange.first != SNRange.second)
9797  {
9798  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9799  {
9800  if(SNIterator->second < 0)
9801  continue; // only looking for inactive (platform or NamedNonStationLocation) elements
9802  if((InactiveTrackElementAt(33, SNIterator->second).TrackType == Platform) || (InactiveTrackElementAt(81,
9803  SNIterator->second).TrackType == NamedNonStationLocation))
9804  {
9805  Utilities->CallLogPop(1121);
9806  return true;
9807  }
9808  }
9809  }
9810  Utilities->CallLogPop(848);
9811  return false;
9812 }
9813 
9814 // ---------------------------------------------------------------------------
9815 
9816 bool TTrack::PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap* &SignalPlatformGraphic)
9817 {
9818 // dropped special platforms at v0.6 as didn't show well against ground signals & not needed anyway as plats always plotted first where there are signals
9819  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlatformOnSignalSide," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
9820  "," + AnsiString(SpeedTag));
9821  if(!IsPlatformOrNamedNonStationLocationPresent(5, HLoc, VLoc)) // can't be a named location so no ambiguity
9822  {
9823  Utilities->CallLogPop(949);
9824  return false;
9825  }
9826  bool FoundFlag;
9827  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(27, HLoc, VLoc, FoundFlag);
9828 
9829  if(!FoundFlag)
9830  {
9831  throw Exception("Error, FoundFlag false in PlatformOnSignalSide after IsPlatformOrNamedNonStationLocationPresent called successfully");
9832  }
9833  TTrackElement IAElement;
9834 
9835  if(SpeedTag == 68) // top sig
9836  {
9837  if((InactiveTrackElementAt(22, IMPair.first).SpeedTag == 76) || (InactiveTrackElementAt(23, IMPair.second).SpeedTag == 76)) // top plat
9838  {
9839  if(InactiveTrackElementAt(49, IMPair.first).SpeedTag == 76)
9840  IAElement = InactiveTrackElementAt(50, IMPair.first);
9841  else
9842  IAElement = InactiveTrackElementAt(51, IMPair.second);
9843  if(IAElement.LocationName == "")
9844  {
9845 // SignalPlatformGraphic = RailGraphics->Plat68Striped;
9846  SignalPlatformGraphic = RailGraphics->gl76Striped;
9847  }
9848  else
9849  {
9850 // SignalPlatformGraphic = RailGraphics->Plat68;
9851  SignalPlatformGraphic = RailGraphics->gl76;
9852  }
9853  Utilities->CallLogPop(950);
9854  return true;
9855  }
9856  }
9857  else if(SpeedTag == 69) // bot sig
9858  {
9859  if((InactiveTrackElementAt(70, IMPair.first).SpeedTag == 77) || (InactiveTrackElementAt(75, IMPair.second).SpeedTag == 77)) // bot plat
9860  {
9861  if(InactiveTrackElementAt(76, IMPair.first).SpeedTag == 77)
9862  IAElement = InactiveTrackElementAt(77, IMPair.first);
9863  else
9864  IAElement = InactiveTrackElementAt(78, IMPair.second);
9865  if(IAElement.LocationName == "")
9866  {
9867 // SignalPlatformGraphic = RailGraphics->Plat69Striped;
9868  SignalPlatformGraphic = RailGraphics->bm77Striped;
9869  }
9870  else
9871  {
9872 // SignalPlatformGraphic = RailGraphics->Plat69;
9873  SignalPlatformGraphic = RailGraphics->bm77;
9874  }
9875  Utilities->CallLogPop(951);
9876  return true;
9877  }
9878  }
9879  else if(SpeedTag == 70) // left sig
9880  {
9881  if((InactiveTrackElementAt(52, IMPair.first).SpeedTag == 78) || (InactiveTrackElementAt(79, IMPair.second).SpeedTag == 78)) // left plat
9882  {
9883  if(InactiveTrackElementAt(80, IMPair.first).SpeedTag == 78)
9884  IAElement = InactiveTrackElementAt(55, IMPair.first);
9885  else
9886  IAElement = InactiveTrackElementAt(82, IMPair.second);
9887  if(IAElement.LocationName == "")
9888  {
9889 // SignalPlatformGraphic = RailGraphics->Plat70Striped;
9890  SignalPlatformGraphic = RailGraphics->bm78Striped;
9891  }
9892  else
9893  {
9894 // SignalPlatformGraphic = RailGraphics->Plat70;
9895  SignalPlatformGraphic = RailGraphics->bm78;
9896  }
9897  Utilities->CallLogPop(952);
9898  return true;
9899  }
9900  }
9901  else if(SpeedTag == 71) // right sig
9902  {
9903  if((InactiveTrackElementAt(83, IMPair.first).SpeedTag == 79) || (InactiveTrackElementAt(58, IMPair.second).SpeedTag == 79)) // right plat
9904  {
9905  if(InactiveTrackElementAt(84, IMPair.first).SpeedTag == 79)
9906  IAElement = InactiveTrackElementAt(85, IMPair.first);
9907  else
9908  IAElement = InactiveTrackElementAt(86, IMPair.second);
9909  if(IAElement.LocationName == "")
9910  {
9911 // SignalPlatformGraphic = RailGraphics->Plat71Striped;
9912  SignalPlatformGraphic = RailGraphics->gl79Striped;
9913  }
9914  else
9915  {
9916 // SignalPlatformGraphic = RailGraphics->Plat71;
9917  SignalPlatformGraphic = RailGraphics->gl79;
9918  }
9919  Utilities->CallLogPop(953);
9920  return true;
9921  }
9922  }
9923  Utilities->CallLogPop(954);
9924  return false;
9925 }
9926 
9927 // ---------------------------------------------------------------------------
9928 
9929 bool TTrack::OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
9930  // returns true if another train on NextEntryPos track of element at NextPos, whether bridge or not
9931  // false if not, if NextPos == -1, or if only own train on the track
9932 {
9933  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OtherTrainOnTrack," + AnsiString(NextPos) + "," +
9934  AnsiString(NextEntryPos) + "," + AnsiString(OwnTrainID));
9935  if(NextEntryPos < 0)
9936  {
9937  Utilities->CallLogPop(1348);
9938  return false;
9939  }
9940  TTrackElement TrackElement = TrackElementAt(713, NextPos);
9941 
9942  if(TrackElement.TrackType != Bridge)
9943  {
9944  Utilities->CallLogPop(1349);
9945  return ((TrackElement.TrainIDOnElement > -1) && (TrackElement.TrainIDOnElement != OwnTrainID));
9946  }
9947 // bridge if reach here
9948  if(NextEntryPos > 1)
9949  {
9950  Utilities->CallLogPop(1350);
9951  return ((TrackElement.TrainIDOnBridgeTrackPos23 > -1) && (TrackElement.TrainIDOnBridgeTrackPos23 != OwnTrainID));
9952  }
9953  else
9954  {
9955  Utilities->CallLogPop(1351);
9956  return ((TrackElement.TrainIDOnBridgeTrackPos01 > -1) && (TrackElement.TrainIDOnBridgeTrackPos01 != OwnTrainID));
9957  }
9958 }
9959 
9960 // ---------------------------------------------------------------------------
9961 
9963 {
9964  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SelectVectorAt," + AnsiString(At));
9965  if((At < 0) || ((unsigned int)At >= SelectVectorSize()))
9966  {
9967  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in SelectVectorAt");
9968  }
9969  Utilities->CallLogPop(1483);
9970  return SelectVector.at(At);
9971 }
9972 
9973 // ---------------------------------------------------------------------------
9974 
9975 bool TTrack::IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
9976  // For element at HLoc & VLoc, returns true if there is an element adjacent to LinkIn
9977 {
9978  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsATrackElementAdjacentToLink," + AnsiString(HLocIn) + "," +
9979  AnsiString(VLocIn) + "," + AnsiString(LinkIn));
9980  bool FoundFlag = false;
9981  int NewHLoc = HLocIn + LinkHVArray[LinkIn][0];
9982  int NewVLoc = VLocIn + LinkHVArray[LinkIn][1];
9983 
9984  GetVectorPositionFromTrackMap(41, NewHLoc, NewVLoc, FoundFlag);
9985  Utilities->CallLogPop(1538);
9986  return FoundFlag;
9987 }
9988 
9989 // ---------------------------------------------------------------------------
9990 
9991 bool TTrack::FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
9992 {
9993 // return true if find an inactive element called 'Name'
9994  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindHighestAndLowestNamedElements," + Name);
9995  int VLocHi = -2000000000, VLocLo = 2000000000, HLoc = 2000000000;
9996  bool FoundFlag = false;
9997 
9998  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9999  {
10000  if(InactiveTrackVector.at(x).LocationName == Name)
10001  {
10002  FoundFlag = true;
10003  int V = InactiveTrackVector.at(x).VLoc;
10004  int H = InactiveTrackVector.at(x).HLoc;
10005  if(V > VLocHi)
10006  VLocHi = V;
10007  if(V < VLocLo)
10008  VLocLo = V;
10009  if(H < HLoc)
10010  HLoc = H;
10011  }
10012  }
10013  if(FoundFlag)
10014  {
10015  VPosHi = 16 * VLocHi;
10016  VPosLo = 16 * VLocLo;
10017  HPos = 16 * HLoc;
10018  Utilities->CallLogPop(1562);
10019  return true;
10020  }
10021  else
10022  {
10023  Utilities->CallLogPop(1563);
10024  return false;
10025  }
10026 }
10027 
10028 // ---------------------------------------------------------------------------
10029 
10030 int TTrack::FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
10031 {
10032 // return the link array position for the element at StartTVPosition that gives the closest link to the element at EndTVPosition
10033 // NB the StartTVPosition is expected to be a single track element as only positions 0 & 1 are checked
10034  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindClosestLinkPosition," + AnsiString(StartTVPosition) + "," +
10035  AnsiString(EndTVPosition));
10036  TTrackElement &StartElement = TrackElementAt(839, StartTVPosition);
10037  TTrackElement &EndElement = TrackElementAt(840, EndTVPosition);
10038 
10039 // get H & V values for the element adjacent to Link[0] & Link[1]
10040  int NewHLocLink0 = StartElement.HLoc + LinkHVArray[StartElement.Link[0]][0];
10041  int NewVLocLink0 = StartElement.VLoc + LinkHVArray[StartElement.Link[0]][1];
10042  int NewHLocLink1 = StartElement.HLoc + LinkHVArray[StartElement.Link[1]][0];
10043  int NewVLocLink1 = StartElement.VLoc + LinkHVArray[StartElement.Link[1]][1];
10044 
10045 // compute the sum of the squares of the H & V distances between EndElement and 'New' values
10046  int Link0Squares = ((EndElement.HLoc - NewHLocLink0) * (EndElement.HLoc - NewHLocLink0)) +
10047  ((EndElement.VLoc - NewVLocLink0) * (EndElement.VLoc - NewVLocLink0));
10048  int Link1Squares = ((EndElement.HLoc - NewHLocLink1) * (EndElement.HLoc - NewHLocLink1)) +
10049  ((EndElement.VLoc - NewVLocLink1) * (EndElement.VLoc - NewVLocLink1));
10050 
10051  if(Link0Squares <= Link1Squares)
10052  {
10053  Utilities->CallLogPop(1851);
10054  return 0;
10055  }
10056  else
10057  {
10058  Utilities->CallLogPop(1852);
10059  return 1;
10060  }
10061 }
10062 
10063 // ---------------------------------------------------------------------------
10064 
10065 int TTrack::GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
10066 { // element can be points or any other type
10067  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAnyElementOppositeLinkPos," + AnsiString(TrackVectorPosition) + "," +
10068  AnsiString(LinkPos));
10069  Derail = false;
10070  TTrackElement &TE = Track->TrackElementAt(277, TrackVectorPosition);
10071 
10072  if((TE.TrackType == Points) && (TE.Config[LinkPos] == Lead))
10073  {
10074  if(TE.Attribute == 0)
10075  {
10076  Utilities->CallLogPop(663);
10077  return 1; // Att == 0 & ExitPos == 1 represent straight
10078  }
10079  else
10080  {
10081  Utilities->CallLogPop(664);
10082  return 3; // Att == 1 & ExitPos == 3 represent diverging
10083  }
10084  }
10085  else if((TE.TrackType == Points) && (TE.Config[LinkPos] == Trail))
10086  {
10087  if((LinkPos == 1) && (TE.Attribute == 0))
10088  {
10089  Utilities->CallLogPop(665);
10090  return 0; // Att == 0 represents straight
10091  }
10092  else if(LinkPos == 1)
10093  {
10094  Derail = true;
10095  Utilities->CallLogPop(666);
10096  return 0;
10097  }
10098  else if((LinkPos == 3) && (TE.Attribute == 1))
10099  {
10100  Utilities->CallLogPop(667);
10101  return 0;
10102  }
10103  else if(LinkPos == 3)
10104  {
10105  Derail = true;
10106  Utilities->CallLogPop(668);
10107  return 0;
10108  }
10109  }
10110  else if(LinkPos == 0)
10111  {
10112  Utilities->CallLogPop(669);
10113  return 1;
10114  }
10115  else if(LinkPos == 1)
10116  {
10117  Utilities->CallLogPop(670);
10118  return 0;
10119  }
10120  else if(LinkPos == 2)
10121  {
10122  Utilities->CallLogPop(671);
10123  return 3;
10124  }
10125  else if(LinkPos == 3)
10126  {
10127  Utilities->CallLogPop(672);
10128  return 2;
10129  }
10130  throw Exception("Error, failure in GetExitPos"); // should never reach here
10131 }
10132 
10133 // ----------------------------------------------------------------------------
10134 
10136 {
10137  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateLCVector");
10138  LCVector.clear();
10139  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
10140  {
10141  if(InactiveTrackVector.at(x).TrackType == LevelCrossing)
10142  {
10143  LCVector.push_back(x);
10144  }
10145  }
10146  Utilities->CallLogPop(1931);
10147  return;
10148 }
10149 
10150 // ---------------------------------------------------------------------------
10151 
10152 bool TTrack::TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID) // new at v1.2.0
10153 /*
10154  Call GetVectorPositionFromTrackMap to identify the track element, then check if TrainIDOnElement > -1 (if a
10155  bridge then check relevant TrainID according to the Link), and if absent return false. If present identify
10156  the train using TrainController->TrainVectorAtIdent, and check which bit on the element in question (Lead, Mid or Lag),
10157  and then check the relevant EntryPos & ExitPos for a match with Link. If find a match return true and return the TrainID.
10158 */
10159 {
10160  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrainOnLink," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
10161  AnsiString(Link));
10162  bool FoundFlag;
10163 
10164  TrainID = -1;
10165  int VecPos = GetVectorPositionFromTrackMap(47, HLoc, VLoc, FoundFlag);
10166 
10167  if(!FoundFlag)
10168  {
10169  Utilities->CallLogPop(2001);
10170  return false;
10171  }
10172  TTrackElement TE = TrackElementAt(882, VecPos);
10173 
10174  TrainID = TE.TrainIDOnElement;
10175  if(TE.TrackType == Bridge)
10176  {
10177  if(TE.TrainIDOnElement > -1)
10178  {
10179  if((TE.Link[0] == Link) || (TE.Link[1] == Link))
10180  {
10181  TrainID = TE.TrainIDOnBridgeTrackPos01;
10182  }
10183  else if((TE.Link[2] == Link) || (TE.Link[3] == Link))
10184  {
10185  TrainID = TE.TrainIDOnBridgeTrackPos23;
10186  }
10187  else
10188  TrainID = -1; // shouldn't ever reach here but be safe
10189  }
10190  }
10191  if(TrainID == -1)
10192  {
10193  Utilities->CallLogPop(2002);
10194  return false;
10195  }
10196 // now get the train
10197  TTrain Train = TrainController->TrainVectorAtIdent(38, TrainID);
10198 
10199  if(Train.LinkOccupied(0, VecPos, Link)) // checks whether any part of train occupying Link on VecPos
10200  {
10201  Utilities->CallLogPop(2003);
10202  return true;
10203  }
10204  TrainID = -1;
10205  Utilities->CallLogPop(2004);
10206  return false;
10207 }
10208 
10209 // ---------------------------------------------------------------------------
10210 
10211 bool TTrack::DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
10212 /* New at v1.2.0
10213  As DiagonalFouledByRouteOrTarin but checks for a train only (may or may not be a route) and returns the ID number. Enter with H & V set for the element whose diagonal
10214  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
10215  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
10216  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
10217  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
10218  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
10219  Each of these is examined in turn for each route element in the relevant position.
10220 */
10221 {
10222  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByTrain," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
10223  "," + AnsiString(DiagonalLinkNumber));
10224  TrainID = -1;
10225  TPrefDirElement TempPrefDirElement;
10226  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
10227 
10228  if(((DiagonalLinkNumber == 1) && TrainOnLink(8, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && TrainOnLink(9, HLoc - 1, VLoc, 9, TrainID)))
10229  {
10230  Utilities->CallLogPop(2027);
10231  return true;
10232  }
10233 
10234  if(((DiagonalLinkNumber == 1) && TrainOnLink(10, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && TrainOnLink(11, HLoc, VLoc - 1, 9, TrainID)))
10235  {
10236  Utilities->CallLogPop(2028);
10237  return true;
10238  }
10239 
10240  if(((DiagonalLinkNumber == 3) && TrainOnLink(12, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(13, HLoc + 1, VLoc, 7, TrainID)))
10241  {
10242  Utilities->CallLogPop(2029);
10243  return true;
10244  }
10245 
10246  if(((DiagonalLinkNumber == 7) && TrainOnLink(14, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(15, HLoc, VLoc + 1, 3, TrainID)))
10247  {
10248  Utilities->CallLogPop(2030);
10249  return true;
10250  }
10251 
10252  Utilities->CallLogPop(2031);
10253  return false;
10254 }
10255 
10256 // ---------------------------------------------------------------------------
10257 
10258 void TTrack::SaveUserGraphics(int Caller, std::ofstream &VecFile)
10259 {
10260  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveUserGraphics");
10261  Utilities->SaveFileInt(VecFile, UserGraphicVector.size()); // number of items
10262  TUserGraphicItem UGI;
10263  AnsiString JustFileName = "";
10264 
10265  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
10266  {
10267  UGI = UserGraphicVectorAt(17, x);
10268  int LastDelim = UGI.FileName.LastDelimiter('\\');
10269  if(LastDelim == 0) // can't find it so skip this item
10270  {
10271  continue;
10272  }
10273  else
10274  {
10275  JustFileName = UGI.FileName.SubString(LastDelim + 1, UGI.FileName.Length() - LastDelim);
10276  }
10277  Utilities->SaveFileString(VecFile, JustFileName);
10278  Utilities->SaveFileInt(VecFile, UGI.HPos);
10279  Utilities->SaveFileInt(VecFile, UGI.VPos);
10280  }
10281  Utilities->CallLogPop(2178);
10282 }
10283 
10284 // ---------------------------------------------------------------------------
10285 
10286 int TTrack::NumberOfPlatforms(int Caller, AnsiString LocationName)
10287 //checks all active track elements and lists those with ActiveTrackElementName same as LocationName in NamePosVector
10288 {
10289  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfPlatforms," + LocationName);
10290  int NumPlats = 0;
10291  TTrackElement TempElement;
10292  int TempInt;
10293 
10294  typedef std::list<int> TNamePosList;
10295  TNamePosList NamePosList;
10296  typedef TNamePosList::iterator TNPLIt;
10297  TNPLIt NPLIt;
10298  typedef std::list<int> TOnePlatList;
10299  TOnePlatList OnePlatList;
10300  typedef TOnePlatList::iterator TOPLIt;
10301  TOPLIt OPLIt;
10302 
10303  NamePosList.clear();
10304  OnePlatList.clear();
10305  for(unsigned int x = 0; x < TrackVector.size(); x++)
10306  {
10307  if(TrackElementAt(988, x).ActiveTrackElementName == LocationName)
10308  {
10309  NamePosList.push_back(x);
10310  }
10311  }
10312  //NamePosList complete
10313 
10314  if(!NamePosList.empty()) //first value for the loop examination
10315  {
10316  OnePlatList.push_back(NamePosList.back());
10317  NamePosList.pop_back(); //erase from NPV as done with it here
10318  }
10319 
10320  while(!OnePlatList.empty()) //loop to examine all linked elements
10321  {
10322  TempInt = OnePlatList.front();
10323  TempElement = TrackElementAt(989, TempInt);
10324 
10325  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[0]);
10326  if(NPLIt != NamePosList.end() && ((TempElement.Link[0] == 2) || (TempElement.Link[0] == 4) || (TempElement.Link[0] == 6) || (TempElement.Link[0] == 8)))
10327  {
10328  OnePlatList.push_back(TempElement.Conn[0]);
10329  NamePosList.erase(NPLIt);
10330  }
10331  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[1]);
10332  if(NPLIt != NamePosList.end() && ((TempElement.Link[1] == 2) || (TempElement.Link[1] == 4) || (TempElement.Link[1] == 6) || (TempElement.Link[1] == 8)))
10333  {
10334  OnePlatList.push_back(TempElement.Conn[1]);
10335  NamePosList.erase(NPLIt);
10336  }
10337  //here when loaded any connecting links into OnePlatList, so can erase the front element
10338  OnePlatList.erase(OnePlatList.begin());
10339  if(OnePlatList.empty())
10340  {
10341  NumPlats++; //finished with current linked elements so can increment NumPlats
10342  if(!NamePosList.empty())
10343  {
10344  OnePlatList.push_back(NamePosList.back()); //ready for next iteration
10345  NamePosList.pop_back(); //erase from NPV as done with it there
10346  }
10347  }
10348  }
10349  Utilities->CallLogPop(2218);
10350  return NumPlats;
10351 }
10352 
10353 // ---------------------------------------------------------------------------
10354 // UserGraphic, PrefDir & Route functions
10355 // ---------------------------------------------------------------------------
10356 
10358 {
10359  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicVectorAt," + AnsiString(At));
10360  if((At < 0) || ((unsigned int)At >= UserGraphicVector.size()))
10361  {
10362  throw Exception("Out of Range Error, vector size: " + AnsiString(UserGraphicVector.size()) + ", At: " + AnsiString(At) + " in UserGraphicVectorAt");
10363  }
10364  Utilities->CallLogPop(2194);
10365  return UserGraphicVector.at(At);
10366 }
10367 
10368 // ---------------------------------------------------------------------------
10369 
10370 int TOnePrefDir::LastElementNumber(int Caller) const
10371 {
10372  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementNumber,");
10373  int RetVal = PrefDirVector.size() - 1;
10374 
10375  if(RetVal < 0)
10376  {
10377  throw Exception("Return value negative in call to LastElementNumber");
10378  }
10379  Utilities->CallLogPop(114);
10380  return RetVal;
10381 }
10382 
10383 // ---------------------------------------------------------------------------
10385 {
10386  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementPtr,");
10387  if(PrefDirVector.empty())
10388  {
10389  throw Exception("PrefDirVector empty in call to LastElementPtr");
10390  }
10391  TPrefDirVectorIterator RetIT = PrefDirVector.end() - 1;
10392 
10393  Utilities->CallLogPop(115);
10394  return RetIT;
10395 }
10396 
10397 // ---------------------------------------------------------------------------
10399 {
10400  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedPrefDirElementAt," + AnsiString(At));
10401  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
10402  {
10403  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) + " in GetFixedPrefDirElementAt");
10404  }
10405  Utilities->CallLogPop(116);
10406  return PrefDirVector.at(At);
10407 }
10408 
10409 // ---------------------------------------------------------------------------
10411 {
10412  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiablePrefDirElementAt," + AnsiString(At));
10413  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
10414  {
10415  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) +
10416  " in GetModifiablePrefDirElementAt");
10417  }
10418  Utilities->CallLogPop(117);
10419  return PrefDirVector.at(At);
10420 }
10421 
10422 // ---------------------------------------------------------------------------
10424 {
10425  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedSearchElementAt," + AnsiString(At));
10426  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
10427  {
10428  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetFixedSearchElementAt");
10429  }
10430  Utilities->CallLogPop(118);
10431  return SearchVector.at(At);
10432 }
10433 
10434 // ---------------------------------------------------------------------------
10436 {
10437  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableSearchElementAt," + AnsiString(At));
10438  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
10439  {
10440  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableSearchElementAt");
10441  }
10442  Utilities->CallLogPop(119);
10443  return SearchVector.at(At);
10444 }
10445 
10446 // ---------------------------------------------------------------------------
10447 bool TOnePrefDir::GetPrefDirStartElement(int Caller, int HLoc, int VLoc) // Return true if OK.
10448 /*
10449  Enter with HLoc & VLoc set to selected element. Clear PrefDirVector, check if selected element
10450  is a valid track element & return false if not. Create a TPrefDirElement from the track element and
10451  set checkcount to 4 to cover the fixed values, then add to PrefDirVector. All variable values are
10452  set in later functions.
10453 */
10454 {
10455  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirStartElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
10456  ClearPrefDir();
10457  int TrackVectorPosition;
10458  TTrackElement TrackElement;
10459 
10460  if(!(Track->FindNonPlatformMatch(5, HLoc, VLoc, TrackVectorPosition, TrackElement)))
10461  {
10462  Utilities->CallLogPop(126);
10463  return false;
10464  }
10465 /* it can be points so drop the code below - all exits are checked, no assumptions are made about the exit position of the start element
10466  if(TrackElement.TrackType == Points)
10467  {
10468  ShowMessage("Can't start on points");//because if PrefDir leads away from the leading edge
10469  //it isn't known which trailing edge is the required PrefDir - could use the straight as
10470  //default but may already be a PrefDir up to the diverging edge, then will have a mismatch,
10471  //best to prevent it to avoid problems
10472  Utilities->CallLogPop(127);
10473  return false;
10474  }
10475 */
10476  TPrefDirElement PrefDirElement(TrackElement);
10477 
10478  PrefDirElement.TrackVectorPosition = TrackVectorPosition;
10479  PrefDirElement.CheckCount = 4; // HLoc, VLoc, SpeedTag & TrackVectorPosition
10480  StorePrefDirElement(1, PrefDirElement); // enter first element
10481 // Note that ELink not set even if a buffer or continuation - these set in
10482 // ConvertPrefDirSearchVector after 2nd element added
10483 
10484  Utilities->CallLogPop(128);
10485  return true;
10486 }
10487 
10488 // ---------------------------------------------------------------------------
10489 bool TOnePrefDir::GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
10490 
10491 /*
10492  Enter with HLoc & VLoc set to selected element. If not a track element or if PrefDirVector empty return false.
10493  Examine the last element in the PrefDirvector, if ELink not set (start element) do an immediate
10494  check for an adjacent find (i.e. find selected element), & if succeed use SearchForPrefDir with that as XLinkPos to deal
10495  with setting the PrefDir vector, & return true. Also set FinishElement if found element was a buffer or continuation,
10496  so that the calling function knows that the PrefDir is complete.
10497  If last element was the start element but no immediate find, search on each valid exit pos in turn, using
10498  SearchForPrefDir to examine all branches. If succeed set PrefDirvector & finishelement as appropriate.
10499  Otherwise (last element not start element) check if last element was a leading point (if so can't be first element)
10500  & check again for an immediate find on either XLinkPos values 1 & 3, using SearchForPrefDir &
10501  ConvertPrefDirSearchVector to set PrefDirVector. Set FinishElement appropriately.
10502  If a leading point but not an immediate find use SearchForPrefDir on the XLinkPos values 1 & 3 in turn.
10503  If it wasn't a leading point just use XLinkPos value corresponding to XLink & Search on that. If don't
10504  find the required element return false. CheckCount is used to keep track of set values to allow check later.
10505 */
10506 
10507 {
10508  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPrefDirElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
10509  FinishElement = false;
10510  int TrackVectorPosition;
10511 
10512  TotalSearchCount = 0;
10513  TTrackElement TrackElement, TempTrackElement;
10514 
10515  if(PrefDirVector.size() == 0)
10516  {
10517  Utilities->CallLogPop(129);
10518  return false;
10519  }
10520  if(!(Track->FindNonPlatformMatch(6, HLoc, VLoc, TrackVectorPosition, TrackElement)))
10521  {
10522  Utilities->CallLogPop(130);
10523  return false;
10524  }
10525 
10526 // set the search limits using the last stored element in PrefDirVector as the start point
10527 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
10528 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
10529 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
10530 
10531  TPrefDirElement StartPrefDirElement = PrefDirVector.at(LastElementNumber(72));
10532 
10533  if(TrackElement.HLoc >= StartPrefDirElement.HLoc)
10534  {
10535  SearchLimitLowH = StartPrefDirElement.HLoc - 15;
10536  SearchLimitHighH = TrackElement.HLoc + 15;
10537  }
10538  else
10539  {
10540  SearchLimitLowH = TrackElement.HLoc - 15;
10541  SearchLimitHighH = StartPrefDirElement.HLoc + 15;
10542  }
10543 
10544  if(TrackElement.VLoc >= StartPrefDirElement.VLoc)
10545  {
10546  SearchLimitLowV = StartPrefDirElement.VLoc - 15;
10547  SearchLimitHighV = TrackElement.VLoc + 15;
10548  }
10549  else
10550  {
10551  SearchLimitLowV = TrackElement.VLoc - 15;
10552  SearchLimitHighV = StartPrefDirElement.VLoc + 15;
10553  }
10554 /* dropped this for v0.4d - prevents ability to set paths for gaps that are widely separated, ok without it as search limited by SearchVector size
10555  check & TotalSearchCounts check
10556  if((abs(TrackElement.HLoc - StartPrefDirElement.HLoc) > 120) || (abs(TrackElement.VLoc - StartPrefDirElement.VLoc) > 120))
10557  {
10558  ShowMessage("Unable to reach the selected element - too far ahead");
10559  Utilities->CallLogPop(1692);
10560  return false;
10561  }
10562 */
10563 // get last PrefDir element
10564  if(PrefDirVector.at(LastElementNumber(0)).ELink == -1) // start element
10565  {
10566  // check if TrackElement adjacent to any of the 4 XLinkPos'
10567  for(int x = 0; x < 4; x++)
10568  {
10569  if(PrefDirVector.at(LastElementNumber(1)).Conn[x] == TrackVectorPosition)
10570  {
10571  PrefDirVector.at(LastElementNumber(2)).XLinkPos = x;
10572  PrefDirVector.at(LastElementNumber(3)).XLink = PrefDirVector.at(LastElementNumber(4)).Link[x];
10573  PrefDirVector.at(LastElementNumber(5)).CheckCount++;
10574  PrefDirVector.at(LastElementNumber(6)).CheckCount++;
10575  break; // can have 2 connections if have 2 adjacent gaps connected to each other but ELink & XLink
10576  // then ambiguous. Have to opt for just one, and if user wanted the other then that's unfortunate,
10577  // shouldn't ever get it in a serious railway though.
10578 // Note: ELink & ELinkPos are set in ConvertPrefDirSearchVector for the start element
10579  }
10580  }
10581  if(PrefDirVector.at(LastElementNumber(7)).XLinkPos > -1) // i.e required position must be adjacent to the start element
10582  {
10583  TempTrackElement = PrefDirVector.at(LastElementNumber(8));
10584  SearchVector.clear(); // use this & convert to set all PrefDir element values
10585  if(SearchForPrefDir(1, TempTrackElement, PrefDirVector.at(LastElementNumber(9)).XLinkPos, TrackVectorPosition))
10586  {
10588  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10589  {
10590  FinishElement = true;
10591  }
10592  Utilities->CallLogPop(131);
10593  return true;
10594  }
10595  } // not an adjacent element
10596 
10597  // now check each of the 4 possible XLinkPos values
10598  for(int x = 0; x < 4; x++)
10599  {
10600  if((PrefDirVector.at(LastElementNumber(10)).Link[x] > 0) && (PrefDirVector.at(LastElementNumber(11)).Config[x] != End)) // i.e have somewhere to go
10601  {
10602  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find the required position
10603  TempTrackElement = PrefDirVector.at(LastElementNumber(12));
10604  SearchVector.clear();
10605  if(SearchForPrefDir(2, TempTrackElement, x, TrackVectorPosition))
10606  {
10608  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10609  {
10610  FinishElement = true;
10611  }
10612  Utilities->CallLogPop(132);
10613  return true;
10614  }
10615  }
10616  } // here if checked all possible exits without success
10617  ShowMessage(
10618  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
10619  Utilities->CallLogPop(133);
10620  return false;
10621  }
10622 // dealt above with LastPrefDirElement being the start element (which can be points)
10623 
10624  if((PrefDirVector.at(LastElementNumber(13)).TrackType == Points) && (PrefDirVector.at(LastElementNumber(14)).Config[PrefDirVector.at(LastElementNumber(15))
10625  .ELinkPos] == Lead)) // leading point
10626  {
10627  if(PrefDirVector.at(LastElementNumber(16)).Conn[1] == TrackVectorPosition) // found it next to XLinkPos = 1
10628  {
10629  PrefDirVector.at(LastElementNumber(17)).XLinkPos = 1;
10630  PrefDirVector.at(LastElementNumber(18)).XLink = PrefDirVector.at(LastElementNumber(19)).Link[1];
10631  // can't be buffers or gap if points
10632  PrefDirVector.at(LastElementNumber(20)).CheckCount++;
10633  PrefDirVector.at(LastElementNumber(21)).CheckCount++;
10634  TempTrackElement = PrefDirVector.at(LastElementNumber(22));
10635  SearchVector.clear();
10636  if(SearchForPrefDir(3, TempTrackElement, 1, TrackVectorPosition)) // bound to return true
10637  {
10639  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10640  {
10641  FinishElement = true;
10642  }
10643  Utilities->CallLogPop(134);
10644  return true;
10645  }
10646  }
10647  if(PrefDirVector.at(LastElementNumber(23)).Conn[3] == TrackVectorPosition) // found it next to XLinkPos = 3
10648  {
10649  PrefDirVector.at(LastElementNumber(24)).XLinkPos = 3;
10650  PrefDirVector.at(LastElementNumber(25)).XLink = PrefDirVector.at(LastElementNumber(26)).Link[3];
10651  PrefDirVector.at(LastElementNumber(27)).CheckCount++;
10652  PrefDirVector.at(LastElementNumber(28)).CheckCount++;
10653  TempTrackElement = PrefDirVector.at(LastElementNumber(29));
10654  SearchVector.clear();
10655  if(SearchForPrefDir(4, TempTrackElement, 3, TrackVectorPosition)) // bound to return true
10656  {
10658  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10659  {
10660  FinishElement = true;
10661  }
10662  Utilities->CallLogPop(135);
10663  return true;
10664  }
10665  }
10666 // above dealt with immediate finds for leading point,
10667 // now deal with ordinary searches for leading point
10668  PrefDirVector.at(LastElementNumber(30)).XLinkPos = 1;
10669  PrefDirVector.at(LastElementNumber(31)).XLink = PrefDirVector.at(LastElementNumber(32)).Link[1];
10670  PrefDirVector.at(LastElementNumber(33)).CheckCount++;
10671  PrefDirVector.at(LastElementNumber(34)).CheckCount++;
10672  TempTrackElement = PrefDirVector.at(LastElementNumber(35));
10673  SearchVector.clear();
10674  if(SearchForPrefDir(5, TempTrackElement, 1, TrackVectorPosition))
10675  {
10677  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10678  {
10679  FinishElement = true;
10680  }
10681  Utilities->CallLogPop(136);
10682  return true;
10683  }
10684  PrefDirVector.at(LastElementNumber(36)).XLinkPos = 3;
10685  PrefDirVector.at(LastElementNumber(37)).XLink = PrefDirVector.at(LastElementNumber(38)).Link[3];
10686  // note that CheckCount already increased to allow for XLinkPos & XLink
10687  TempTrackElement = PrefDirVector.at(LastElementNumber(39));
10688  SearchVector.clear();
10689  if(SearchForPrefDir(6, TempTrackElement, 3, TrackVectorPosition))
10690  {
10692  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10693  {
10694  FinishElement = true;
10695  }
10696  Utilities->CallLogPop(137);
10697  return true;
10698  }
10699 // here if failed to find match for leading point
10700  PrefDirVector.at(LastElementNumber(69)).CheckCount--; // to removed the earlier increments for XLinkPos & XLink
10701  PrefDirVector.at(LastElementNumber(70)).CheckCount--;
10702  ShowMessage(
10703  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
10704  Utilities->CallLogPop(138);
10705  return false;
10706  }
10707 // leading point fully dealt with above
10708 // here with an ordinary element, just do an ordinary search - no need to search for an immediate find
10709 // separately as covered in ordinary search.
10710 
10711  TempTrackElement = PrefDirVector.at(LastElementNumber(40));
10712  SearchVector.clear();
10713 // no need to check for valid XLinkPos as not start element and not end element or would not reach here
10714  if(SearchForPrefDir(7, TempTrackElement, PrefDirVector.at(LastElementNumber(41)).XLinkPos, TrackVectorPosition))
10715  {
10717  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10718  {
10719  FinishElement = true;
10720  }
10721  Utilities->CallLogPop(139);
10722  return true;
10723  }
10724  ShowMessage(
10725  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
10726  Utilities->CallLogPop(140);
10727  return false; // failed to find required element
10728 }
10729 
10730 // ---------------------------------------------------------------------------
10731 
10732 bool TOnePrefDir::SearchForPrefDir(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition)
10733 /*
10734  Enter with CurrentTrackElement stored in the PrefDirVector, XLinkPos set to the link
10735  to search on, & SearchVector cleared unless entered recursively. Function is a continuous loop that
10736  exits when find required element (returns true) or reaches a buffer or continuation or otherwise fails a search condition (returns false).
10737  Keep a count of entries in SearchVector during the current function call, so that this number can be
10738  erased for an unproductive branch search.
10739  Create a NextTrackElement from Current & XLinkPos as far as possible, & check if found required
10740  element. If so save it & return true. If not check if buffer, continuation, or earlier position
10741  in SearchVector or PrefDirVector, & if so erase all searchvector & return false. If OK check if a leading point and
10742  if so do up to 2 recursive searches for the 2 exits. If fail on both erase searchvector & return false.
10743  If not any of above, store element in searchvector, set the new current element values from the
10744  SearchElement, then go back to the while loop for the next step in the search.
10745 */
10746 {
10747  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPrefDir," + CurrentTrackElement.LogTrack(13) + "," +
10748  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition));
10749  int VectorCount = 0;
10750 
10751  while(true)
10752  {
10753  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
10754  {
10755  for(int x = 0; x < VectorCount; x++)
10756  SearchVector.erase(SearchVector.end() - 1);
10757  Utilities->CallLogPop(141);
10758  return false;
10759  }
10760  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
10761  TTrackElement NextTrackElement = Track->TrackElementAt(74, NextPosition);
10762  TPrefDirElement SearchElement(NextTrackElement);
10763  SearchElement.TrackVectorPosition = NextPosition;
10764  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
10765  SearchElement.ELinkPos = NextELinkPos;
10766  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
10767  int NextXLinkPos;
10768  if(SearchElement.ELinkPos == 0)
10769  NextXLinkPos = 1;
10770  if(SearchElement.ELinkPos == 1)
10771  NextXLinkPos = 0;
10772  if(SearchElement.ELinkPos == 2)
10773  NextXLinkPos = 3;
10774  if(SearchElement.ELinkPos == 3)
10775  NextXLinkPos = 2;
10776  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
10777  {
10778  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
10779  // but may be buffers, continuation or gap
10780  SearchElement.XLinkPos = NextXLinkPos;
10781  }
10782 // can't set XLink or XLinkPos yet if the element is a leading point.
10783 // check if found it
10784  if(SearchElement.TrackVectorPosition == RequiredPosition)
10785  {
10786  SearchVector.push_back(SearchElement); // XLink & XLinkPos won't be set if a leading point
10787  VectorCount++; // not really needed but include for tidyness
10788  TotalSearchCount++;
10789  Utilities->CallLogPop(142);
10790  return true;
10791  }
10792 // check if PrefDirVector > 200 and if so reject further searches (to avoid possible problems in converting
10793 // very long vectors) - warning given in ConvertPrefDirSearchVector, though can still add elements one
10794 // at a time - drop this
10795 /*
10796  if(PrefDirVector.size() > 200)
10797  {
10798  for(int x=0;x<VectorCount;x++) SearchVector.erase(SearchVector.end() - 1);
10799  Utilities->CallLogPop(1419);
10800  return false;
10801  }
10802 */
10803 // check if a buffer or continuation
10804  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
10805  {
10806  for(int x = 0; x < VectorCount; x++)
10807  SearchVector.erase(SearchVector.end() - 1);
10808  Utilities->CallLogPop(143);
10809  return false;
10810  }
10811 // check if reached an earlier position on search PrefDir with same entry value
10812  for(unsigned int x = 0; x < SearchVector.size(); x++)
10813  {
10814  if((SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition) && (SearchElement.ELink == SearchVector.at(x).ELink))
10815  {
10816  for(int x = 0; x < VectorCount; x++)
10817  SearchVector.erase(SearchVector.end() - 1);
10818  Utilities->CallLogPop(144);
10819  return false;
10820  }
10821  }
10822 // check if reached an earlier position in the PrefDirVector with same entry value (without this can keep adding entries
10823 // to PrefDir4MultiMap, and since only 4 are searched an error can occur)
10824  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
10825  {
10826  if((SearchElement.TrackVectorPosition == PrefDirVector.at(x).TrackVectorPosition) && (SearchElement.ELink == PrefDirVector.at(x).ELink))
10827  {
10828  for(int x = 0; x < VectorCount; x++)
10829  SearchVector.erase(SearchVector.end() - 1);
10830  Utilities->CallLogPop(1417);
10831  return false;
10832  }
10833  }
10834 
10835 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
10836 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
10837 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
10839  {
10840  for(int x = 0; x < VectorCount; x++)
10841  SearchVector.erase(SearchVector.end() - 1);
10842  Utilities->CallLogPop(1691);
10843  return false;
10844  }
10845 
10846 // check if SearchVector reached 150, and if so reject, to save time in searching for PrefDirs
10847  if(SearchVector.size() > 150)
10848  {
10849  for(int x = 0; x < VectorCount; x++)
10850  SearchVector.erase(SearchVector.end() - 1);
10851  Utilities->CallLogPop(1418);
10852  return false;
10853  }
10854 // check if reached a leading point
10855  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
10856  {
10857 // push element with XLink set to position [1]
10858  SearchElement.XLink = SearchElement.Link[1];
10859  SearchElement.XLinkPos = 1;
10860  SearchVector.push_back(SearchElement);
10861  VectorCount++;
10862  TotalSearchCount++;
10863  // recursive search at XLinkPos of 1 (i.e. 1st trailing exit)
10864  // Note that have to use a TTrackElement in the recursive search, so SearchElement
10865  // can't be used. NextTrackElement is the corresponding TTrackElement.
10866  if(SearchForPrefDir(8, NextTrackElement, 1, RequiredPosition))
10867  {
10868  Utilities->CallLogPop(145);
10869  return true;
10870  }
10871  else
10872  {
10873 // remove leading point with XLinkPos [1]
10874  SearchVector.erase(SearchVector.end() - 1);
10875  VectorCount--;
10876 // push element with XLink set to position [3]
10877  SearchElement.XLink = SearchElement.Link[3];
10878  SearchElement.XLinkPos = 3;
10879  SearchVector.push_back(SearchElement);
10880  VectorCount++;
10881  TotalSearchCount++;
10882 // recursive search at XLinkPos of 3 (i.e. 2nd trailing exit)
10883  if(SearchForPrefDir(9, NextTrackElement, 3, RequiredPosition))
10884  {
10885  Utilities->CallLogPop(146);
10886  return true;
10887  }
10888  else
10889  {
10890  for(int x = 0; x < VectorCount; x++)
10891  SearchVector.erase(SearchVector.end() - 1);
10892  Utilities->CallLogPop(147);
10893  return false;
10894  }
10895  }
10896  } // if leading point
10897 // here if ordinary element, push it, inc vector & update CurrentTrackElement
10898 // ready for next element on PrefDir
10899  SearchVector.push_back(SearchElement);
10900  VectorCount++;
10901  TotalSearchCount++;
10902  XLinkPos = NextXLinkPos;
10903  CurrentTrackElement = SearchElement;
10904  } // while(true)
10905 }
10906 
10907 // ---------------------------------------------------------------------------
10908 
10910 /*
10911  Enter with SearchVector established. This contains ELink + Pos, XLink + Pos, & TrackVectorPosition
10912  for each element on the search PrefDir, though if the last element is a leading point
10913  then the final XLink won't be set.
10914  Note also that the last element in the PrefDirVector (as opposed to the searchvector) may not have its ELink set (if it was the start)
10915  nor its XLink set (if it was the start or a leading point), so these are checked first and together with EXNumber set as necessary.
10916  The remaining PrefDirVector elements are then set from the searchvector & checkcount keeps pace as values are added.
10917 */
10918 {
10919  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertPrefDirSearchVector");
10920  if(SearchVector.size() == 0)
10921  {
10922  throw Exception("Error, SearchVector empty");
10923  }
10924 // get first SearchElement in order to set last PrefDirelement
10925  TPrefDirElement SearchElement = SearchVector.at(0);
10926 
10927 // set last PrefDir element XLink & ELink values if not already set
10928 // ELink & XLink not set if was first element in PrefDir; XLink also not set if was a leading point
10929  for(int x = 0; x < 4; x++)
10930  {
10931  if(PrefDirVector.at(LastElementNumber(42)).Conn[x] == SearchElement.TrackVectorPosition)
10932  {
10933  if(PrefDirVector.at(LastElementNumber(43)).XLink == -1) // i.e. not set
10934  {
10935  PrefDirVector.at(LastElementNumber(44)).XLink = PrefDirVector.at(LastElementNumber(45)).Link[x];
10936  PrefDirVector.at(LastElementNumber(46)).XLinkPos = x;
10937  PrefDirVector.at(LastElementNumber(47)).CheckCount++;
10938  PrefDirVector.at(LastElementNumber(48)).CheckCount++;
10939  }
10940  int ELinkPos;
10941  if(PrefDirVector.at(LastElementNumber(49)).XLinkPos == 0)
10942  ELinkPos = 1; // use actual value rather than 'x' as may be a gap
10943  // with both ends linked to 1st searchvector element, & if XLink was set then x may not correspond
10944  if(PrefDirVector.at(LastElementNumber(50)).XLinkPos == 1)
10945  ELinkPos = 0;
10946  if(PrefDirVector.at(LastElementNumber(51)).XLinkPos == 2)
10947  ELinkPos = 3;
10948  if(PrefDirVector.at(LastElementNumber(52)).XLinkPos == 3)
10949  ELinkPos = 2;
10950  if(PrefDirVector.at(LastElementNumber(53)).ELink == -1) // because was start element
10951  {
10952  PrefDirVector.at(LastElementNumber(54)).ELink = PrefDirVector.at(LastElementNumber(55)).Link[ELinkPos];
10953  PrefDirVector.at(LastElementNumber(56)).ELinkPos = ELinkPos;
10954  PrefDirVector.at(LastElementNumber(57)).CheckCount++;
10955  PrefDirVector.at(LastElementNumber(58)).CheckCount++;
10956  }
10957  break; // no point going any further
10958  }
10959  }
10960 // set EXNumber for last PrefDir element, unless already set
10961 // won't be set if was first element or a leading point
10962  if(PrefDirVector.at(LastElementNumber(59)).EXNumber == -1)
10963  {
10964 /* The order for entries & exits is as follows (1st no = entry, 2nd = exit):-
10965  int EXArray[32][2] = {
10966  {4,6},{2,8}, //horizontal & vertical
10967  {2,4},{6,2},{8,6},{4,8}, //sharp curves
10968  {1,6},{3,8},{9,4},{7,2},{1,8},{3,4},{9,2},{7,6}, //loose curves
10969  {1,9},{3,7} //forward & reverse diagonals
10970 */
10971 
10972  if(!(PrefDirVector.at(LastElementNumber(60)).EntryExitNumber()))
10973  {
10974  throw Exception("Error in EntryExitNumber 1");
10975  }
10976 
10977  PrefDirVector.at(LastElementNumber(61)).EXGraphicPtr = PrefDirVector.at(LastElementNumber(62)).GetPrefDirGraphicPtr();
10978  PrefDirVector.at(LastElementNumber(63)).EntryDirectionGraphicPtr = PrefDirVector.at(LastElementNumber(64)).GetDirectionPrefDirGraphicPtr();
10979  PrefDirVector.at(LastElementNumber(65)).CheckCount++;
10980  }
10981 // Last PrefDir element now complete
10982 
10983 // construct remaining PrefDir elements from searchvector
10984  for(unsigned int x = 0; x < SearchVector.size(); x++)
10985  {
10986  SearchElement = SearchVector.at(x);
10987  TPrefDirElement PrefDirElement(Track->TrackElementAt(75, SearchElement.TrackVectorPosition));
10988  PrefDirElement.TrackVectorPosition = SearchElement.TrackVectorPosition;
10989  PrefDirElement.ELink = SearchElement.ELink;
10990  PrefDirElement.ELinkPos = SearchElement.ELinkPos;
10991  PrefDirElement.XLink = SearchElement.XLink;
10992  PrefDirElement.XLinkPos = SearchElement.XLinkPos;
10993 // if XLink & XLinkPos not set don't account for them in CheckCount
10994  if(PrefDirElement.XLink == -1)
10995  PrefDirElement.CheckCount = 6; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
10996  // & TrackVectorPosition
10997  else
10998  PrefDirElement.CheckCount = 8; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
10999  // XLink, XLinkPos, TrackVectorPosition
11000 
11001 // set EXNumber (can't set EXNumber if XLink not set - if finished on a leading point
11002  if(PrefDirElement.XLink != -1)
11003  {
11004  if(!(PrefDirElement.EntryExitNumber()))
11005  {
11006  throw Exception("Error in EntryExitNumber 2");
11007  }
11008  PrefDirElement.EXGraphicPtr = PrefDirElement.GetPrefDirGraphicPtr();
11009  PrefDirElement.EntryDirectionGraphicPtr = PrefDirElement.GetDirectionPrefDirGraphicPtr();
11010  PrefDirElement.CheckCount++;
11011  // all values now incorporated if not a leading point
11012  }
11013 // store PrefDir element
11014  StorePrefDirElement(2, PrefDirElement);
11015  }
11016 // Can now validate if PrefDir finished, i.e. if buffers or continuation, else validate when 'AddPrefDir' button pressed
11017  if((LastElementPtr(0)->TrackType == Buffers) || (LastElementPtr(1)->TrackType == Continuation))
11018  {
11019  if(ValidatePrefDir(2))
11020  {;
11021  } // error messages given within function
11022  }
11024 /* drop this, check dropped from search
11025  if(PrefDirVector.size() > 200)
11026  {
11027  ShowMessage("The selected track segment is becoming too long, until it is accepted further elements can only be added one at a time");
11028  }
11029 */
11030  Utilities->CallLogPop(148);
11031 }
11032 
11033 // ---------------------------------------------------------------------------
11034 
11035 bool TOnePrefDir::EndPossible(int Caller, bool &LeadingPoints)
11036 /*
11037  Return true if selected element is valid as a PrefDir end element, i.e. isn't leading points,
11038  and PrefDir isn't one element long. Used to enable the AddPrefDirButton during PrefDir building.
11039 */
11040 {
11041  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EndPossible");
11042  LeadingPoints = false;
11043  if(PrefDirVector.empty())
11044  {
11045  Utilities->CallLogPop(1786);
11046  return false; // should never be empty but allow for it for safety
11047  }
11048  if(PrefDirVector.size() == 1)
11049  {
11050  Utilities->CallLogPop(149);
11051  return false; // can't end if only one element
11052  }
11053 /*
11054  if((PrefDirVector.at(LastElementNumber()).TrackType != Points) &&
11055  (PrefDirVector.at(LastElementNumber()).TrackType != Crossover))
11056  {
11057  Utilities->CallLogPop(150);
11058  return true;
11059  }
11060 */
11061 // allow for anything but leading points
11062  if((PrefDirVector.at(LastElementNumber(66)).TrackType != Points) || (PrefDirVector.at(LastElementNumber(67)).ELinkPos == 1) ||
11063  (PrefDirVector.at(LastElementNumber(71)).ELinkPos == 3))
11064  {
11065  Utilities->CallLogPop(1776);
11066  return true;
11067  }
11068  else
11069  {
11070  LeadingPoints = true;
11071  Utilities->CallLogPop(151);
11072  return false;
11073  }
11074 }
11075 
11076 // ---------------------------------------------------------------------------
11077 
11079 /*
11080  Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default values,
11081  and that every element is connected to the next element
11082 */
11083 {
11084  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ValidatePrefDir");
11085  int Position;
11086  AnsiString ErrorString;
11087  bool Error = false;
11088 
11089  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11090  {
11091  if(PrefDirVector.at(x).HLoc == -2000000000)
11092  {
11093  Error = true;
11094  ErrorString = "HLoc";
11095  Position = x;
11096  }
11097  if(PrefDirVector.at(x).VLoc == -2000000000)
11098  {
11099  Error = true;
11100  ErrorString = "VLoc";
11101  Position = x;
11102  }
11103  if(PrefDirVector.at(x).ELink == -1)
11104  {
11105  Error = true;
11106  ErrorString = "ELink";
11107  Position = x;
11108  }
11109  if(PrefDirVector.at(x).ELinkPos == -1)
11110  {
11111  Error = true;
11112  ErrorString = "ELinkPos";
11113  Position = x;
11114  }
11115  if(PrefDirVector.at(x).XLink == -1)
11116  {
11117  Error = true;
11118  ErrorString = "XLink";
11119  Position = x;
11120  }
11121  if(PrefDirVector.at(x).XLinkPos == -1)
11122  {
11123  Error = true;
11124  ErrorString = "XLinkPos";
11125  Position = x;
11126  }
11127  if(PrefDirVector.at(x).SpeedTag == 0)
11128  {
11129  Error = true;
11130  ErrorString = "Tag";
11131  Position = x;
11132  }
11133  if(PrefDirVector.at(x).TrackVectorPosition == -1)
11134  {
11135  Error = true;
11136  ErrorString = "TrackVectorPosition";
11137  Position = x;
11138  }
11139  if(PrefDirVector.at(x).EXNumber == -1)
11140  {
11141  Error = true;
11142  ErrorString = "EXNumber";
11143  Position = x;
11144  }
11145  if(PrefDirVector.at(x).CheckCount != 9)
11146  // HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink, ELinkPos, XLink, XLinkPos & EXNumber
11147  {
11148  Error = true;
11149  ErrorString = "CheckCount";
11150  Position = x;
11151  }
11152 // extra checks
11153  if(PrefDirVector.at(x).EXGraphicPtr == 0)
11154  {
11155  Error = true;
11156  ErrorString = "EntryGraphicPtr";
11157  Position = x;
11158  }
11159  if(PrefDirVector.at(x).EntryDirectionGraphicPtr == 0)
11160  {
11161  Error = true;
11162  ErrorString = "EntryDirectionGraphicPtr";
11163  Position = x;
11164  }
11165 // end of extra checks
11166  if(x > 0)
11167  {
11168  if(PrefDirVector.at(x - 1).Conn[PrefDirVector.at(x - 1).XLinkPos] != PrefDirVector.at(x).TrackVectorPosition)
11169  {
11170  Error = true;
11171  ErrorString = "Last XLink not connected to this element";
11172  Position = x;
11173  }
11174  }
11175  }
11176  if(Error)
11177  {
11178  throw Exception("Error at " + AnsiString(Position) + " " + ErrorString);
11179  }
11180  else
11181  {
11182  Utilities->CallLogPop(153);
11183  return true;
11184  }
11185 }
11186 
11187 // ---------------------------------------------------------------------------
11188 
11189 bool TOnePrefDir::GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
11190 /*
11191  This is only called during PrefDir build or distance setting. It truncates at & including the first element in the PrefDir vector
11192  that matches H & V. After the truncate the final element of the remaining PrefDir has its data members reset
11193  to the same defaults as would be the case if the PrefDir had been built up to that point - i.e. for first element
11194  or a leading point.
11195 */
11196 {
11197  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11198  for(unsigned int x = 0; x < (PrefDirVector.size()); x++)
11199  {
11200  if((PrefDirVector.at(x).HLoc == HLoc) && (PrefDirVector.at(x).VLoc == VLoc))
11201  {
11202  for(int PrefDirVecPos = (PrefDirVector.size() - 1); PrefDirVecPos >= (int)x; PrefDirVecPos--) // has to be int or will underflow at x==0
11203  {
11204  ErasePrefDirElementAt(1, PrefDirVecPos);
11205  }
11206  if(PrefDirVector.size() == 0)
11207  {
11208  Utilities->CallLogPop(154);
11209  return true;
11210  }
11211  if(PrefDirVector.size() == 1)
11212  {
11213  PrefDirVector.at(x - 1).ELinkPos = -1;
11214  PrefDirVector.at(x - 1).ELink = -1;
11215  PrefDirVector.at(x - 1).XLinkPos = -1;
11216  PrefDirVector.at(x - 1).XLink = -1;
11217  PrefDirVector.at(x - 1).EXNumber = -1;
11218  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
11219  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
11220  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 5;
11221  Utilities->CallLogPop(155);
11222  return true;
11223  }
11224  // here with truncate element not first element, so ELink & ELinkPos set
11225  // unset XLink & Pos if a leading point
11226  if(PrefDirVector.at(x - 1).Config[PrefDirVector.at(x - 1).ELinkPos] == Lead)
11227  {
11228  PrefDirVector.at(x - 1).XLinkPos = -1;
11229  PrefDirVector.at(x - 1).XLink = -1;
11230  PrefDirVector.at(x - 1).EXNumber = -1;
11231  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
11232  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
11233  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 3;
11234  Utilities->CallLogPop(156);
11235  return true;
11236  }
11237  Utilities->CallLogPop(157);
11238  return true;
11239  }
11240  }
11241  Utilities->CallLogPop(158);
11242  return false;
11243 }
11244 
11245 // ---------------------------------------------------------------------------
11246 
11247 void TOnePrefDir::PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp)
11248  const // PrefDirRoute = PrefDircall or routecall for PrefDir or route; true for BuildingPrefDir
11249 /*
11250  PrefDir and route track marker, including direction markers. Function used for both PrefDirs (PrefDirRoute == PrefDirCall) and routes
11251  (PrefDirRoute == RouteCall). The graphics for marker colours and direction are already stored in all PrefDirElements in
11252  TOnePrefDir and TOneRoute, and this function is called to display them, all in the case of a PrefDir, but for a route only the
11253  first and last elements have direction markers. No markers are displayed if a train is present on an element. Also no
11254  display if EXGraphicPtr not set. If building a PrefDir (BuildingPrefDir true) then the start and end rectangles are also
11255  displayed.
11256 */
11257 {
11258  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PrefDirMarker," + AnsiString(PrefDirRoute) + "," +
11259  AnsiString((short)BuildingPrefDir));
11260  int HPos, VPos;
11261 
11262  if(PrefDirSize() == 0)
11263  {
11264  Utilities->CallLogPop(159);
11265  return;
11266  }
11267  for(unsigned int x = 0; x < PrefDirSize(); x++)
11268  {
11269  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
11270 // if(Track->TrackElementAt(76, TempPrefDirElement.TrackVectorPosition).TrainIDOnElement > -1) continue;
11271 // don't plot route element if train present - dropped above as train departing only replotted the part of the route
11272 // that the train was on. Ensure though that whenever plot a route replot trains after else route will overwrite train
11273  // without the above, if route replotted in ClearandRebuildRailway when train is straddling 3 elements
11274  // and before the next train update, then the route element corresponding to the LagElement will be plotted,
11275  // only the front half of which will be overplotted by the back of the train, then when the train is
11276  // updated the route image will remain plotted and stay on screen until a later ClearandRebuildRailway
11277  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
11278  {
11279  Disp->PlotOutput(12, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EXGraphicPtr);
11280  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == PrefDirCall)) // PrefDir
11281  {
11282  Disp->PlotOutput(13, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
11283  }
11284  else if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == RouteCall) && PrefDirSize() > 1)
11285  // Route, no direction if a single element
11286  {
11287  if(x == 0)
11288  {
11289  Disp->PlotOutput(14, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
11290  }
11291  if(x == (PrefDirSize() - 1))
11292  {
11293  Disp->PlotOutput(15, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
11294  }
11295  }
11296  }
11297  }
11298 
11299 // set start & end element colours if building a PrefDir
11300  if((PrefDirRoute == PrefDirCall) && BuildingPrefDir)
11301  {
11302  HPos = GetFixedPrefDirElementAt(4, 0).HLoc * 16;
11303  VPos = GetFixedPrefDirElementAt(5, 0).VLoc * 16;
11304  Disp->Rectangle(1, HPos, VPos, clB0G0R5, 2, 2); // medium red rectangle
11305  // set last element colour
11306  if(PrefDirSize() > 1)
11307  {
11308  unsigned int LatestPos = PrefDirSize() - 1;
11309  HPos = GetFixedPrefDirElementAt(6, LatestPos).HLoc * 16;
11310  VPos = GetFixedPrefDirElementAt(7, LatestPos).VLoc * 16;
11311  Disp->Rectangle(2, HPos, VPos, clB5G0R0, 4, 2); // smaller blue rectangle
11312  }
11313  }
11314  Disp->Update();
11315  Utilities->CallLogPop(160);
11316 }
11317 
11318 // ---------------------------------------------------------------------------
11319 
11321 /*
11322  Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green for bidirectional
11323  Colours taken from the route colours. Plot red first so green overwrites for bidirectional points.
11324 */
11325 {
11326  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EveryPrefDirMarker");
11327  if(PrefDirSize() == 0)
11328  {
11329  Utilities->CallLogPop(1547);
11330  return;
11331  }
11332 
11333  int H, V, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
11334  bool FoundFlag;
11336  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
11337 
11338  while(MMIT != PrefDir4MultiMap.end())
11339  {
11340  H = MMIT->first.first;
11341  V = MMIT->first.second;
11342  GetVectorPositionsFromPrefDir4MultiMap(6, H, V, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
11343  // always found in order, any missing have PrefDirPosx == -1
11344  if(PrefDirPos0 > -1)
11345  PrefDirElement0 = GetFixedPrefDirElementAt(170, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
11346  if(PrefDirPos1 > -1)
11347  PrefDirElement1 = GetFixedPrefDirElementAt(171, PrefDirPos1);
11348  if(PrefDirPos2 > -1)
11349  PrefDirElement2 = GetFixedPrefDirElementAt(172, PrefDirPos2);
11350  if(PrefDirPos3 > -1)
11351  PrefDirElement3 = GetFixedPrefDirElementAt(173, PrefDirPos3);
11352  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
11353  { // need to plot all 4 in order to obtain all the direction graphics
11354  Disp->PlotOutput(77, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
11355  Disp->PlotOutput(78, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
11356  Disp->PlotOutput(79, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
11357  Disp->PlotOutput(80, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
11358  Disp->PlotOutput(81, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
11359  Disp->PlotOutput(82, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
11360  Disp->PlotOutput(83, (H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
11361  Disp->PlotOutput(84, (H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
11362  MMIT++;
11363  MMIT++;
11364  MMIT++;
11365  MMIT++;
11366  }
11367  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
11368  {
11369  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
11370  { // 0 & 1 constitute the bidirectional PrefDir
11371  Disp->PlotOutput(89, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
11372  Disp->PlotOutput(90, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
11373  Disp->PlotOutput(85, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
11374  Disp->PlotOutput(86, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
11375  Disp->PlotOutput(87, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
11376  Disp->PlotOutput(88, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
11377  MMIT++;
11378  MMIT++;
11379  MMIT++;
11380  }
11381  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
11382  { // 0 & 2 constitute the bidirectional PrefDir
11383  Disp->PlotOutput(95, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
11384  Disp->PlotOutput(96, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
11385  Disp->PlotOutput(91, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
11386  Disp->PlotOutput(92, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
11387  Disp->PlotOutput(93, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
11388  Disp->PlotOutput(94, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
11389  MMIT++;
11390  MMIT++;
11391  MMIT++;
11392  }
11393  else
11394  { // 1 & 2 constitute the bidirectional PrefDir
11395  Disp->PlotOutput(101, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
11396  Disp->PlotOutput(102, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
11397  Disp->PlotOutput(97, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
11398  Disp->PlotOutput(98, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
11399  Disp->PlotOutput(99, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
11400  Disp->PlotOutput(100, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
11401  MMIT++;
11402  MMIT++;
11403  MMIT++;
11404  }
11405  }
11406  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
11407  {
11408  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
11409  { // 0 & 1 constitute the bidirectional PrefDir
11410  Disp->PlotOutput(103, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
11411  Disp->PlotOutput(104, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
11412  Disp->PlotOutput(105, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
11413  Disp->PlotOutput(106, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
11414  MMIT++;
11415  MMIT++;
11416  }
11417  else
11418  { // 2 unidirectional PrefDirs
11419  Disp->PlotOutput(107, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
11420  Disp->PlotOutput(108, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
11421  Disp->PlotOutput(109, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
11422  Disp->PlotOutput(110, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
11423  MMIT++;
11424  MMIT++;
11425  }
11426  }
11427  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
11428  {
11429  Disp->PlotOutput(111, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
11430  Disp->PlotOutput(112, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
11431  MMIT++;
11432  }
11433  }
11434  Disp->Update();
11435  Utilities->CallLogPop(1548);
11436 }
11437 
11438 // ---------------------------------------------------------------------------
11439 
11440 void TOnePrefDir::LoadOldPrefDir(int Caller, std::ifstream &VecFile)
11441 {
11442  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOldPrefDir");
11443  int TempInt;
11444 
11445  ClearPrefDir();
11446  int NumberOfPrefDirElements = 0;
11447 
11448  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
11449  for(int x = 0; x < NumberOfPrefDirElements; x++)
11450  {
11451  VecFile >> TempInt; // TrackVectorPosition
11452  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(714, TempInt));
11453  LoadPrefDirElement.TrackVectorPosition = TempInt;
11454  VecFile >> TempInt;
11455  LoadPrefDirElement.ELink = TempInt;
11456  VecFile >> TempInt;
11457  LoadPrefDirElement.ELinkPos = TempInt;
11458  VecFile >> TempInt;
11459  LoadPrefDirElement.XLink = TempInt;
11460  VecFile >> TempInt;
11461  LoadPrefDirElement.XLinkPos = TempInt;
11462  VecFile >> TempInt;
11463  LoadPrefDirElement.EXNumber = TempInt;
11464  VecFile >> TempInt;
11465  LoadPrefDirElement.CheckCount = TempInt;
11466  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
11467  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
11468  LoadPrefDirElement.ConsecSignals = Utilities->LoadFileBool(VecFile);
11469  if(!(LoadPrefDirElement.IsARoute))
11470  {
11471  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
11472  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
11473  }
11474  else
11475  {
11476  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.ConsecSignals);
11477  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
11478  LoadPrefDirElement.ConsecSignals);
11479  }
11480  StorePrefDirElement(5, LoadPrefDirElement);
11481  Utilities->LoadFileString(VecFile); // marker
11482  }
11484  Utilities->CallLogPop(161);
11485 }
11486 
11487 // ---------------------------------------------------------------------------
11488 
11489 void TOnePrefDir::LoadPrefDir(int Caller, std::ifstream &VecFile)
11490 {
11491  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPrefDir");
11492  int TempInt;
11493 
11494  ClearPrefDir();
11495  int NumberOfPrefDirElements = 0;
11496 
11497  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
11498  for(int x = 0; x < NumberOfPrefDirElements; x++)
11499  {
11500  VecFile >> TempInt; // PrefDirVectorPosition, not used in load
11501  VecFile >> TempInt; // TrackVectorPosition
11502  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(781, TempInt));
11503  LoadPrefDirElement.TrackVectorPosition = TempInt;
11504  VecFile >> TempInt;
11505  LoadPrefDirElement.ELink = TempInt;
11506  VecFile >> TempInt;
11507  LoadPrefDirElement.ELinkPos = TempInt;
11508  VecFile >> TempInt;
11509  LoadPrefDirElement.XLink = TempInt;
11510  VecFile >> TempInt;
11511  LoadPrefDirElement.XLinkPos = TempInt;
11512  VecFile >> TempInt;
11513  LoadPrefDirElement.EXNumber = TempInt;
11514  VecFile >> TempInt;
11515  LoadPrefDirElement.CheckCount = TempInt;
11516  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
11517  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
11518  LoadPrefDirElement.ConsecSignals = Utilities->LoadFileBool(VecFile);
11519  if(!(LoadPrefDirElement.IsARoute))
11520  {
11521  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
11522  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
11523  }
11524  else
11525  {
11526  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.ConsecSignals);
11527  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
11528  LoadPrefDirElement.ConsecSignals);
11529  }
11530  StorePrefDirElement(0, LoadPrefDirElement);
11531  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // marker
11532  }
11534  Utilities->CallLogPop(1509);
11535 }
11536 
11537 // ---------------------------------------------------------------------------
11538 
11539 bool TOnePrefDir::CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile) // returns false if no more PrefDirs to check
11540 /*
11541  Called before PrefDir loading as part of the FileIntegrityCheck function, in case there is an error in the
11542  file. Very similar to LoadPrefDir but with value checks instead of storage in PrefDirVector.
11543 */
11544 {
11545  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckOnePrefDir");
11546  int TempInt;
11547  int NumberOfPrefDirElements = 0;
11548 
11549  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
11550  if((NumberOfPrefDirElements < 0) || (NumberOfPrefDirElements > 1000000))
11551  {
11552  Utilities->CallLogPop(1152);
11553  return false;
11554  }
11555  for(int x = 0; x < NumberOfPrefDirElements; x++)
11556  {
11557  if(!Utilities->CheckFileInt(VecFile, x, x)) // vector number
11558  {
11559  Utilities->CallLogPop(1766);
11560  return false;
11561  }
11562  VecFile >> TempInt;
11563  if((TempInt < 0) || (TempInt >= NumberOfActiveElements)) // TrackVectorPosition
11564  {
11565  Utilities->CallLogPop(163);
11566  return false;
11567  }
11568  VecFile >> TempInt;
11569  if((TempInt < -1) || (TempInt > 9)) // ELink
11570  {
11571  Utilities->CallLogPop(162);
11572  return false;
11573  }
11574  VecFile >> TempInt;
11575  if((TempInt < -1) || (TempInt > 3)) // ELinkPos
11576  {
11577  Utilities->CallLogPop(164);
11578  return false;
11579  }
11580  VecFile >> TempInt;
11581  if((TempInt < -1) || (TempInt > 9)) // XLink
11582  {
11583  Utilities->CallLogPop(165);
11584  return false;
11585  }
11586  VecFile >> TempInt;
11587  if((TempInt < -1) || (TempInt > 3)) // XLinkPos
11588  {
11589  Utilities->CallLogPop(166);
11590  return false;
11591  }
11592  VecFile >> TempInt;
11593  if((TempInt < -1) || (TempInt > 27)) // EXNumber
11594  {
11595  Utilities->CallLogPop(167);
11596  return false;
11597  }
11598  VecFile >> TempInt;
11599  if(TempInt != 9) // CheckCount - reduced to 11 after NextPrefDirElement dropped &
11600  // to 9 after End & Stop dropped. Leaving HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink,
11601  // ELinkPos, XLink, XLinkPos & EXNumber
11602  {
11603  Utilities->CallLogPop(168);
11604  return false;
11605  }
11606  VecFile >> TempInt;
11607  if((TempInt != 0) && (TempInt != 1)) // RouteElement
11608  {
11609  Utilities->CallLogPop(1147);
11610  return false;
11611  }
11612  VecFile >> TempInt;
11613  if((TempInt != 0) && (TempInt != 1)) // AutoSignals
11614  {
11615  Utilities->CallLogPop(1510);
11616  return false;
11617  }
11618  VecFile >> TempInt;
11619  if((TempInt != 0) && (TempInt != 1)) // ConsecSignals
11620  {
11621  Utilities->CallLogPop(1148);
11622  return false;
11623  }
11624  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // marker
11625  {
11626  Utilities->CallLogPop(1700);
11627  return false;
11628  }
11629  }
11630  Utilities->CallLogPop(169);
11631  return true;
11632 }
11633 
11634 // ---------------------------------------------------------------------------
11635 
11636 void TOnePrefDir::SavePrefDirVector(int Caller, std::ofstream &VecFile)
11637 {
11638  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePrefDir");
11639  int NumberOfPrefDirElements = PrefDirVector.size();
11640 
11641  Utilities->SaveFileInt(VecFile, NumberOfPrefDirElements);
11642  for(int y = 0; y < NumberOfPrefDirElements; y++)
11643  {
11644  VecFile << y << '\n'; // extra
11645  VecFile << PrefDirVector.at(y).TrackVectorPosition << '\n';
11646  VecFile << PrefDirVector.at(y).ELink << '\n';
11647  VecFile << PrefDirVector.at(y).ELinkPos << '\n';
11648  VecFile << PrefDirVector.at(y).XLink << '\n';
11649  VecFile << PrefDirVector.at(y).XLinkPos << '\n';
11650  VecFile << PrefDirVector.at(y).EXNumber << '\n';
11651  VecFile << PrefDirVector.at(y).CheckCount << '\n';
11652  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).IsARoute);
11653  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).AutoSignals);
11654  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).ConsecSignals);
11655  if(y == (NumberOfPrefDirElements - 1)) // last element, write a longer delimiter
11656  {
11657  VecFile << "************" << '\0' << '\n'; // marker
11658  }
11659  else
11660  {
11661  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
11662  }
11663  }
11664  Utilities->CallLogPop(170);
11665 }
11666 
11667 // ---------------------------------------------------------------------------
11668 
11669 void TOnePrefDir::SaveSearchVector(int Caller, std::ofstream &VecFile)
11670 {
11671  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSearchVector");
11672  int NumberOfSearchElements = SearchVector.size();
11673 
11674  Utilities->SaveFileInt(VecFile, NumberOfSearchElements);
11675  for(int y = 0; y < NumberOfSearchElements; y++)
11676  {
11677  VecFile << y << '\n'; // extra
11678  VecFile << SearchVector.at(y).TrackVectorPosition << '\n';
11679  VecFile << SearchVector.at(y).ELink << '\n';
11680  VecFile << SearchVector.at(y).ELinkPos << '\n';
11681  VecFile << SearchVector.at(y).XLink << '\n';
11682  VecFile << SearchVector.at(y).XLinkPos << '\n';
11683  VecFile << SearchVector.at(y).EXNumber << '\n';
11684  VecFile << SearchVector.at(y).CheckCount << '\n';
11685  Utilities->SaveFileBool(VecFile, SearchVector.at(y).IsARoute);
11686  Utilities->SaveFileBool(VecFile, SearchVector.at(y).AutoSignals);
11687  Utilities->SaveFileBool(VecFile, SearchVector.at(y).ConsecSignals);
11688  if(y == (NumberOfSearchElements - 1)) // last element, write a longer delimiter
11689  {
11690  VecFile << "************" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
11691  }
11692  else
11693  {
11694  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
11695  }
11696  }
11697  Utilities->CallLogPop(1847);
11698 }
11699 
11700 // ---------------------------------------------------------------------------
11701 
11702 void TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
11703 /*
11704  Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails
11705  erasing up to four elements (2 directions and 2 tracks for 4-entry elements).
11706 */
11707 {
11708  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseFromPrefDirVectorAnd4MultiMap," + AnsiString(HLoc) + "," +
11709  AnsiString(VLoc));
11710  int VecPos = GetOnePrefDirPosition(1, HLoc, VLoc);
11711 
11712  if(VecPos > -1)
11713  ErasePrefDirElementAt(2, VecPos); // max of 4 to be erased
11714  else
11715  {
11716  Utilities->CallLogPop(171);
11717  return;
11718  }
11719  VecPos = GetOnePrefDirPosition(2, HLoc, VLoc);
11720  if(VecPos > -1)
11721  ErasePrefDirElementAt(3, VecPos);
11722  else
11723  {
11724  Utilities->CallLogPop(172);
11725  return;
11726  }
11727  VecPos = GetOnePrefDirPosition(3, HLoc, VLoc);
11728  if(VecPos > -1)
11729  ErasePrefDirElementAt(4, VecPos);
11730  else
11731  {
11732  Utilities->CallLogPop(173);
11733  return;
11734  }
11735  VecPos = GetOnePrefDirPosition(4, HLoc, VLoc);
11736  if(VecPos > -1)
11737  ErasePrefDirElementAt(5, VecPos);
11738  else
11739  {
11740  Utilities->CallLogPop(174);
11741  return;
11742  }
11743  Utilities->CallLogPop(175);
11744 }
11745 
11746 // ---------------------------------------------------------------------------
11747 /*
11748  void TOnePrefDir::EraseCorruptedElementsAfterTrackBuild()//Delete any PrefDir elements that are no longer valid
11749  //Not needed after new TrackErase (now EraseTrackElement), where blank elements aren't used
11750 
11751  When track is rebuilt any elements that are dispensed with aren't erased immediately, a blank element is put
11752  in their place so that existing linkages will be preserved. At this stage this function is called to remove
11753  any elements in PrefDirVector that correspond directly to blank track elements or that are connected to blank track
11754  elements. Finally the track is reconnected using Track->TryToConnectTrack (if won't connect then returns to
11755  AddTrackStage build mode for corrections to be made) and then EveryPrefDir->RebuildPrefDirVector() called to reset
11756  PrefDirVector to correspond to the new track layout.
11757 
11758  {
11759  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EraseCorruptedElementsAfterTrackBuild");
11760  if(PrefDirSize() == 0)
11761  {
11762  Utilities->CallLogPop(176);
11763  return;
11764  }
11765  for(int x=(PrefDirVector.size()-1);x>=0;x--)
11766  {
11767  int TV = PrefDirVector.at(x).TrackVectorPosition;
11768  int ConnELink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).ELinkPos];
11769  int ConnXLink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).XLinkPos];
11770  if(Track->BlankElementAt(0, TV))
11771  {
11772  ErasePrefDirElementAt(6, x);
11773  }
11774  //if was a blankelement at x then ConnELink and ConnXLink both -1
11775  else if((ConnELink > -1) && (Track->BlankElementAt(1, ConnELink)))
11776  {
11777  ErasePrefDirElementAt(7, x);
11778  }
11779  //if both ConnELink and ConnXLink correspond to blank elements then OK, element only
11780  //needs to be erased once, but if don't use 'else' then will erase two elements
11781  //since 'x' will correspond to the element after the first erased element
11782  else if((ConnXLink > -1) && (Track->BlankElementAt(2, ConnXLink)))
11783  {
11784  ErasePrefDirElementAt(8, x);
11785  }
11786  }
11787  Utilities->CallLogPop(177);
11788  }
11789 */
11790 // ---------------------------------------------------------------------------
11791 
11792 void TOnePrefDir::ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
11793 /*
11794  This is used to add InputPrefDir's PrefDirVector to TOnePrefDir's PrefDirVector except where it already
11795  exists in TOnePrefDir. In practice it adds ConstructPrefDir to EveryPrefDir.
11796 */
11797 {
11798  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConsolidatePrefDirs");
11799  bool AlreadyPresent, FoundFlag;
11800  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
11801 
11802  for(unsigned int x = 0; x < InputPrefDir->PrefDirSize(); x++)
11803  {
11804  TPrefDirElement TempElement = InputPrefDir->PrefDirVector.at(x);
11805  GetVectorPositionsFromPrefDir4MultiMap(1, TempElement.HLoc, TempElement.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
11806  AlreadyPresent = false;
11807  if(FoundFlag)
11808  {
11809  if((PrefDirPos0 > -1) && (TempElement == GetFixedPrefDirElementAt(8, PrefDirPos0)))
11810  AlreadyPresent = true;
11811  if((PrefDirPos1 > -1) && (TempElement == GetFixedPrefDirElementAt(9, PrefDirPos1)))
11812  AlreadyPresent = true;
11813  if((PrefDirPos2 > -1) && (TempElement == GetFixedPrefDirElementAt(10, PrefDirPos2)))
11814  AlreadyPresent = true;
11815  if((PrefDirPos3 > -1) && (TempElement == GetFixedPrefDirElementAt(11, PrefDirPos3)))
11816  AlreadyPresent = true;
11817  }
11818  if(!AlreadyPresent)
11819  StorePrefDirElement(4, TempElement);
11820  }
11822  Utilities->CallLogPop(178);
11823 }
11824 /* earlier brute force search
11825  for(unsigned int x = 0;x<InputPrefDir->PrefDirSize();x++)
11826  {
11827  TPrefDirElement TempElement = InputPrefDir->GetFixedPrefDirElementAt(12, x);
11828  bool AlreadyPresent = false;
11829  for(unsigned int y = 0;y<PrefDirSize();y++)
11830  {
11831  if(TempElement == GetFixedPrefDirElementAt(13, y)) AlreadyPresent = true;
11832  }
11833  if(!AlreadyPresent) StorePrefDirElement(, TempElement);
11834  }
11835 */
11836 
11837 // ---------------------------------------------------------------------------
11838 
11840 /*
11841  Rebuild from Trackmap, doesn't affect PrefDir4MultiMap.
11842  After a track build, but before the track is reconnected, all invalid PrefDir elements in TOnePrefDir
11843  (i.e. in EveryPrefDir) are erased. Hence at that stage all the PrefDir elements are valid and correspond to
11844  the track elements at relevant H & V positions. However, after the track is reconnected, the TrackVector
11845  positions are likely to have changed, so this function is called to reset all the necessary connections and
11846  TrackVector positions. To be on the safe side all the TrackElement values that are additional to
11847  TFixedTrackPiece (apart from TrainIDs, these only present during operation) are reset, though the others
11848  shouldn't have changed.
11849 */
11850 {
11851  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildPrefDirVector");
11852  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11853  {
11854  bool FoundFlag;
11855  int VecPos = Track->GetVectorPositionFromTrackMap(10, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
11856  if(FoundFlag)
11857  {
11858  PrefDirVector.at(x).TrackVectorPosition = VecPos;
11859  PrefDirVector.at(x).LocationName = Track->TrackElementAt(78, VecPos).LocationName;
11860  PrefDirVector.at(x).ActiveTrackElementName = Track->TrackElementAt(79, VecPos).ActiveTrackElementName;
11861  PrefDirVector.at(x).ElementID = Track->TrackElementAt(80, VecPos).ElementID;
11862  PrefDirVector.at(x).Attribute = Track->TrackElementAt(81, VecPos).Attribute;
11863  for(unsigned int z = 0; z < 4; z++)
11864  {
11865  PrefDirVector.at(x).Conn[z] = Track->TrackElementAt(82, VecPos).Conn[z];
11866  PrefDirVector.at(x).ConnLinkPos[z] = Track->TrackElementAt(83, VecPos).ConnLinkPos[z];
11867  }
11868  }
11869  else
11870  {
11871  throw Exception("Error in RebuildPrefDirVector - PrefDirVector is unsafe");
11872  }
11873  }
11874  Utilities->CallLogPop(179);
11875 }
11876 
11877 // ---------------------------------------------------------------------------
11878 
11880 /*
11881  Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefDir & PrefDir4MultiMap.
11882 */
11883 {
11884  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVector");
11885  bool DiscrepancyFound = false;
11886 
11887  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11888  {
11889  bool FoundFlag;
11890  int VecPos = Track->GetVectorPositionFromTrackMap(39, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
11891  if(FoundFlag)
11892  {
11893  TPrefDirElement PE = PrefDirVector.at(x);
11894  if(PE.TrackVectorPosition != VecPos)
11895  DiscrepancyFound = true;
11896  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
11897  {
11898  DiscrepancyFound = true;
11899  break;
11900  }
11901  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
11902  {
11903  DiscrepancyFound = true;
11904  break;
11905  }
11906  if(PE.ELink != Track->TrackElementAt(710, VecPos).Link[PE.GetELinkPos()])
11907  {
11908  DiscrepancyFound = true;
11909  break;
11910  }
11911  if(PE.XLink != Track->TrackElementAt(711, VecPos).Link[PE.GetXLinkPos()])
11912  {
11913  DiscrepancyFound = true;
11914  break;
11915  }
11916  }
11917  else
11918  DiscrepancyFound = true;
11919  }
11920  if(DiscrepancyFound)
11921  {
11922  ShowMessage("Discrepancies found in the preferred direction file, preferred directions will be cleared");
11923  ClearPrefDir(); // also clears multimap
11924  }
11925  Utilities->CallLogPop(1436);
11926 }
11927 
11928 // ---------------------------------------------------------------------------
11929 
11931 /*
11932  Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4MultiMap.
11933  return true for OK
11934 */
11935 {
11936  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVectorNoMessage");
11937  bool DiscrepancyFound = false;
11938 
11939  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11940  {
11941  bool FoundFlag;
11942  int VecPos = Track->GetVectorPositionFromTrackMap(36, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
11943  if(FoundFlag)
11944  {
11945  TPrefDirElement PE = PrefDirVector.at(x);
11946  if(PE.TrackVectorPosition != VecPos)
11947  DiscrepancyFound = true;
11948  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
11949  {
11950  DiscrepancyFound = true;
11951  break;
11952  }
11953  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
11954  {
11955  DiscrepancyFound = true;
11956  break;
11957  }
11958  if(PE.ELink != Track->TrackElementAt(715, VecPos).Link[PE.GetELinkPos()])
11959  {
11960  DiscrepancyFound = true;
11961  break;
11962  }
11963  if(PE.XLink != Track->TrackElementAt(716, VecPos).Link[PE.GetXLinkPos()])
11964  {
11965  DiscrepancyFound = true;
11966  break;
11967  }
11968  }
11969  else
11970  DiscrepancyFound = true;
11971  }
11972  Utilities->CallLogPop(1512);
11973  return !DiscrepancyFound;
11974 }
11975 
11976 // ---------------------------------------------------------------------------
11977 
11978 void TOnePrefDir::CheckPrefDir4MultiMap(int Caller) // test
11979 /*
11980  Test function to check correspondence between PrefDirVector and PrefDir4MultiMap for each element in
11981  turn and for the overall sizes.
11982 */
11983 {
11984  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDir4MultiMap");
11985  bool FoundFlag = false;
11986  int PrefDir0, PrefDir1, PrefDir2, PrefDir3;
11987 
11988  for(unsigned int a = 0; a < PrefDirVector.size(); a++)
11989  {
11990  TPrefDirElement CheckElement = PrefDirVector.at(a);
11991  GetVectorPositionsFromPrefDir4MultiMap(2, CheckElement.HLoc, CheckElement.VLoc, FoundFlag, PrefDir0, PrefDir1, PrefDir2, PrefDir3);
11992  if(!FoundFlag)
11993  {
11994  throw Exception("CheckPrefDir4MultiMap Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
11995  " in PrefDir4MultiMap, Caller=" + (AnsiString)Caller);
11996  }
11997  if((PrefDir0 != (int)a) && (PrefDir1 != (int)a) && (PrefDir2 != (int)a) && (PrefDir3 != (int)a))
11998  {
11999  throw Exception("CheckPrefDir4MultiMap Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
12000  (AnsiString)CheckElement.VLoc + " Map values=" + (AnsiString)PrefDir0 + ", " + (AnsiString)PrefDir1 + ", " + (AnsiString)PrefDir2 + ", " +
12001  (AnsiString)PrefDir3 + " PrefDirVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
12002  }
12003  }
12004  if(PrefDirVector.size() != PrefDir4MultiMap.size())
12005  {
12006  throw Exception("CheckPrefDir4MultiMap Error - Map Size=" + (AnsiString)PrefDirVector.size() + " PrefDirVectorSize=" + (AnsiString)PrefDirVector.size()
12007  + " Caller=" + (AnsiString)Caller);
12008  }
12009  Utilities->CallLogPop(180);
12010 }
12011 
12012 // ---------------------------------------------------------------------------
12013 
12014 void TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2,
12015  int &PrefDirPos3)
12016 /*
12017  There are up to four elements at each H & V position in the PrefDirVector - two directions, and up to
12018  two tracks for 4-entry elements. This function retrieves all elements that are present at a give H & V
12019  position. FoundFlag indicates whether any or none have been found, and PrefDirPos0, 1, 2 & 3 contain
12020  the PrefDirVector positions, or -1 if not present. The elements are always found in order, such that
12021  if there is only one it will be in PrefDirPos0, if two they will be in PrefDirPos0 and PrefDirPos1 and so on.
12022 */
12023 {
12024  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromPrefDir4MultiMap," + AnsiString(HLoc) + "," +
12025  AnsiString(VLoc));
12026  THVPair PrefDirMapKeyPair;
12027 
12028  PrefDirPos0 = -1;
12029  PrefDirPos1 = -1;
12030  PrefDirPos2 = -1;
12031  PrefDirPos3 = -1;
12032  FoundFlag = false;
12033  PrefDirMapKeyPair.first = HLoc;
12034  PrefDirMapKeyPair.second = VLoc;
12035  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
12036 
12037  ItPair = PrefDir4MultiMap.equal_range(PrefDirMapKeyPair);
12038  if(ItPair.first == ItPair.second)
12039  {
12040  Utilities->CallLogPop(181);
12041  return;
12042  }
12043  else
12044  {
12045  FoundFlag = true;
12046  PrefDirPos0 = ItPair.first->second;
12047  ItPair.first++;
12048  if(ItPair.first == ItPair.second)
12049  {
12050  Utilities->CallLogPop(182);
12051  return;
12052  }
12053  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
12054  PrefDirPos1 = ItPair.first->second;
12055  ItPair.first++;
12056  if(ItPair.first == ItPair.second)
12057  {
12058  Utilities->CallLogPop(183);
12059  return;
12060  }
12061  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
12062  PrefDirPos2 = ItPair.first->second;
12063  ItPair.first++;
12064  if(ItPair.first == ItPair.second)
12065  {
12066  Utilities->CallLogPop(184);
12067  return;
12068  }
12069  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
12070  PrefDirPos3 = ItPair.first->second;
12071  }
12072  Utilities->CallLogPop(185);
12073 }
12074 
12075 // ---------------------------------------------------------------------------
12076 
12077 void TOnePrefDir::StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
12078 /*
12079  LoadPrefDirElement is stored in both the PrefDirVector and in PrefDir4MultiMap.
12080 */
12081 {
12082  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StorePrefDirElement," + LoadPrefDirElement.LogPrefDir());
12083  PrefDirVector.push_back(LoadPrefDirElement);
12084  THVPair PrefDir4MultiMapKeyPair;
12085  TPrefDir4MultiMapEntry PrefDir4MultiMapEntry;
12086 
12087  PrefDir4MultiMapKeyPair.first = LoadPrefDirElement.HLoc;
12088  PrefDir4MultiMapKeyPair.second = LoadPrefDirElement.VLoc;
12089  PrefDir4MultiMapEntry.first = PrefDir4MultiMapKeyPair;
12090  PrefDir4MultiMapEntry.second = LastElementNumber(68);
12091  PrefDir4MultiMap.insert(PrefDir4MultiMapEntry);
12092 // CheckPrefDir4MultiMap(1);Drop here as takes too long - call it by each calling function
12093  Utilities->CallLogPop(186);
12094 }
12095 
12096 // ---------------------------------------------------------------------------
12097 
12098 void TOnePrefDir::ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
12099 /*
12100  Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNumbers in
12101  4MultiMap if they are greater than the erased value.
12102 */
12103 {
12104  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErasePrefDirElementAt," + AnsiString(PrefDirVectorPosition));
12105  bool FoundFlag;
12106 
12107  if(!PrefDirVector.empty())
12108  {
12109  TPrefDir4MultiMapIterator EraseIt = GetExactMatchFrom4MultiMap(0, PrefDirVectorPosition, FoundFlag);
12110  if(!FoundFlag)
12111  {
12112  throw Exception("Failed to find PrefDir4MultiMap erase element");
12113  }
12114  PrefDirVector.erase(PrefDirVector.begin() + PrefDirVectorPosition);
12115  PrefDir4MultiMap.erase(EraseIt);
12116  DecrementPrefDirElementNumbersInPrefDir4MultiMap(0, PrefDirVectorPosition);
12118  }
12119  Utilities->CallLogPop(187);
12120 }
12121 
12122 // ---------------------------------------------------------------------------
12123 
12124 void TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
12125 /*
12126  Called after ErasePrefDirElementAt(int PrefDirVectorPosition) to decrement the remaining PrefDirElementNumbers in
12127  4MultiMap if they are greater than the erased value.
12128 */
12129 {
12130  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementPrefDirElementNumbersInPrefDir4MultiMap," +
12131  AnsiString(ErasedElementNumber));
12132  if(!PrefDir4MultiMap.empty())
12133  {
12134  for(TPrefDir4MultiMapIterator MapPtr = PrefDir4MultiMap.begin(); MapPtr != PrefDir4MultiMap.end(); MapPtr++)
12135  {
12136  if(MapPtr->second > ErasedElementNumber)
12137  MapPtr->second--;
12138  }
12139  }
12140  Utilities->CallLogPop(1450);
12141 }
12142 
12143 // ---------------------------------------------------------------------------
12144 
12145 TOnePrefDir::TPrefDir4MultiMapIterator TOnePrefDir::GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
12146 /*
12147  Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition. Used during
12148  ErasePrefDirElementAt(int PrefDirVectorPosition) to erase the relevant element in the multimap. If
12149  nothing is found this is an error but the error message is given in the calling function.
12150 */
12151 {
12152  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetExactMatchFrom4MultiMap," + AnsiString(PrefDirVectorPosition));
12153  FoundFlag = false;
12154  if(PrefDirVectorPosition >= PrefDirVector.size())
12155  {
12156  throw Exception("PrefDirVectorPosition out of range");
12157  }
12158  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(14, PrefDirVectorPosition);
12159  THVPair PrefDir4MultiMapKeyPair;
12160 
12161  PrefDir4MultiMapKeyPair.first = PrefDirElement.HLoc;
12162  PrefDir4MultiMapKeyPair.second = PrefDirElement.VLoc;
12163  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
12164 
12165  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
12166  if(ItPair.first == ItPair.second)
12167  {
12168  Utilities->CallLogPop(188);
12169  return ItPair.first; // nothing found but have to return an iterator, FoundFlag indicates nothing found
12170  }
12171  else
12172  {
12173  if(ItPair.first->second == PrefDirVectorPosition)
12174  {
12175  FoundFlag = true;
12176  Utilities->CallLogPop(189);
12177  return ItPair.first;
12178  }
12179  ItPair.first++;
12180  if(ItPair.first == ItPair.second)
12181  {
12182  Utilities->CallLogPop(190);
12183  return ItPair.first; // nothing found
12184  }
12185  if(ItPair.first->second == PrefDirVectorPosition)
12186  {
12187  FoundFlag = true;
12188  Utilities->CallLogPop(191);
12189  return ItPair.first;
12190  }
12191  ItPair.first++;
12192  if(ItPair.first == ItPair.second)
12193  {
12194  Utilities->CallLogPop(192);
12195  return ItPair.first; // nothing found
12196  }
12197  if(ItPair.first->second == PrefDirVectorPosition)
12198  {
12199  FoundFlag = true;
12200  Utilities->CallLogPop(193);
12201  return ItPair.first;
12202  }
12203  ItPair.first++;
12204  if(ItPair.first == ItPair.second)
12205  {
12206  Utilities->CallLogPop(194);
12207  return ItPair.first; // nothing found
12208  }
12209  if(ItPair.first->second == PrefDirVectorPosition)
12210  {
12211  FoundFlag = true;
12212  Utilities->CallLogPop(195);
12213  return ItPair.first;
12214  }
12215  }
12216  Utilities->CallLogPop(196);
12217  return ItPair.first; // nothing found
12218 }
12219 
12220 // ---------------------------------------------------------------------------
12221 
12222 int TOnePrefDir::GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
12223 /*
12224  Although there may be up to four entries at one H & V position this function gets just one. It is
12225  used in EraseFromPrefDirVectorAnd4MultiMap by being called as many times as there are PrefDir elements
12226  at H & V.
12227 */
12228 {
12229  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetOnePrefDirPosition," + AnsiString(HLoc) + "," + AnsiString(VLoc));
12230  THVPair PrefDir4MultiMapKeyPair;
12231 
12232  PrefDir4MultiMapKeyPair.first = HLoc;
12233  PrefDir4MultiMapKeyPair.second = VLoc;
12234  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
12235 
12236  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
12237  if(ItPair.first == ItPair.second) // nothing found
12238  {
12239  Utilities->CallLogPop(197);
12240  return -1;
12241  }
12242  else
12243  {
12244  Utilities->CallLogPop(198);
12245  return ItPair.first->second;
12246  }
12247 }
12248 
12249 // ---------------------------------------------------------------------------
12250 
12251 void TOnePrefDir::RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
12252 {
12253  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RealignAfterTrackErase," + AnsiString(ErasedTrackVectorPosition));
12254  bool ErasedFlag = false;
12255 
12256  if(ErasedTrackVectorPosition > -1) // should be in calling function but include here as a safeguard
12257  {
12258  if(PrefDirSize() == 0)
12259  {
12260  Utilities->CallLogPop(1511);
12261  return;
12262  }
12263  for(int x = (PrefDirSize() - 1); x >= 0; x--) // reverse because of erase
12264  {
12265  ErasedFlag = false;
12266  // use 'else' to ensure don't try to access an erased element
12267  if(PrefDirVector.at(x).TrackVectorPosition == ErasedTrackVectorPosition)
12268  {
12269  ErasePrefDirElementAt(11, x);
12270  ErasedFlag = true;
12271  }
12272  else if(PrefDirVector.at(x).Conn[0] == ErasedTrackVectorPosition)
12273  {
12274  ErasePrefDirElementAt(12, x);
12275  ErasedFlag = true;
12276  }
12277  else if(PrefDirVector.at(x).Conn[1] == ErasedTrackVectorPosition)
12278  {
12279  ErasePrefDirElementAt(13, x);
12280  ErasedFlag = true;
12281  }
12282  else if(PrefDirVector.at(x).Conn[2] == ErasedTrackVectorPosition)
12283  {
12284  ErasePrefDirElementAt(9, x);
12285  ErasedFlag = true;
12286  }
12287  else if(PrefDirVector.at(x).Conn[3] == ErasedTrackVectorPosition)
12288  {
12289  ErasePrefDirElementAt(10, x);
12290  ErasedFlag = true;
12291  }
12292  if(!ErasedFlag)
12293  {
12294  // don't use 'else' here as may be more than one that need decrementing
12295  if(PrefDirVector.at(x).TrackVectorPosition > ErasedTrackVectorPosition)
12296  {
12297  PrefDirVector.at(x).TrackVectorPosition--;
12298  }
12299  if(PrefDirVector.at(x).Conn[0] > ErasedTrackVectorPosition)
12300  {
12301  PrefDirVector.at(x).Conn[0]--;
12302  }
12303  if(PrefDirVector.at(x).Conn[1] > ErasedTrackVectorPosition)
12304  {
12305  PrefDirVector.at(x).Conn[1]--;
12306  }
12307  if(PrefDirVector.at(x).Conn[2] > ErasedTrackVectorPosition)
12308  {
12309  PrefDirVector.at(x).Conn[2]--;
12310  }
12311  if(PrefDirVector.at(x).Conn[3] > ErasedTrackVectorPosition)
12312  {
12313  PrefDirVector.at(x).Conn[3]--;
12314  }
12315  }
12316  }
12317  }
12318  Utilities->CallLogPop(1434);
12319 }
12320 
12321 // ---------------------------------------------------------------------------
12322 
12323 void TOnePrefDir::CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
12324 {
12325  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcDistanceAndSpeed");
12326  OverallDistance = 0;
12327  OverallSpeedLimit = 0;
12328  LeadingPointsAtLastElement = false;
12329  if(PrefDirSize() == 0) // shouldn't be empty when this called
12330  {
12331  Utilities->CallLogPop(1491);
12332  return;
12333  }
12334 
12335  if((LastElementPtr(21)->TrackType == Points) && (LastElementPtr(22)->ELinkPos != 1) && (LastElementPtr(23)->ELinkPos != 3))
12336  {
12337  LeadingPointsAtLastElement = true;
12338  Utilities->CallLogPop(1492);
12339  return;
12340  }
12341  for(unsigned int x = 0; x < PrefDirSize(); x++)
12342  {
12343  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(166, x);
12344  if((PrefDirElement.GetELinkPos() > 1) || (PrefDirElement.GetXLinkPos() > 1)) // 'or' because points may have one == 0 & other == 3
12345  {
12346  OverallDistance += PrefDirElement.Length23;
12347  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
12348  {
12349  if(x == 0)
12350  {
12351  OverallSpeedLimit = PrefDirElement.SpeedLimit23;
12352  }
12353  else
12354  {
12355  if(OverallSpeedLimit != PrefDirElement.SpeedLimit23)
12356  {
12357  OverallSpeedLimit = -1;
12358  }
12359  }
12360  }
12361  }
12362  else
12363  {
12364  OverallDistance += PrefDirElement.Length01;
12365  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
12366  {
12367  if(x == 0)
12368  {
12369  OverallSpeedLimit = PrefDirElement.SpeedLimit01;
12370  }
12371  else
12372  {
12373  if(OverallSpeedLimit != PrefDirElement.SpeedLimit01)
12374  {
12375  OverallSpeedLimit = -1;
12376  }
12377  }
12378  }
12379  }
12380  }
12381  Utilities->CallLogPop(1529);
12382 }
12383 
12384 // ---------------------------------------------------------------------------
12385 
12386 void TOnePrefDir::WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
12387 {
12388  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WritePrefDirToImage");
12389  if(PrefDirSize() == 0)
12390  {
12391  Utilities->CallLogPop(1564);
12392  return;
12393  }
12394 
12395  int H, V, HLoc, VLoc, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12396  bool FoundFlag;
12398  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
12399 
12400  while(MMIT != PrefDir4MultiMap.end())
12401  {
12402  HLoc = MMIT->first.first;
12403  VLoc = MMIT->first.second;
12404  GetVectorPositionsFromPrefDir4MultiMap(7, HLoc, VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12405  H = HLoc - Track->GetHLocMin();
12406  V = VLoc - Track->GetVLocMin();
12407  // always found in order, any missing have PrefDirPosx == -1
12408  if(PrefDirPos0 > -1)
12409  PrefDirElement0 = GetFixedPrefDirElementAt(174, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
12410  if(PrefDirPos1 > -1)
12411  PrefDirElement1 = GetFixedPrefDirElementAt(175, PrefDirPos1);
12412  if(PrefDirPos2 > -1)
12413  PrefDirElement2 = GetFixedPrefDirElementAt(176, PrefDirPos2);
12414  if(PrefDirPos3 > -1)
12415  PrefDirElement3 = GetFixedPrefDirElementAt(177, PrefDirPos3);
12416  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
12417  { // need to plot all 4 in order to obtain all the direction graphics
12418  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12419  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12420  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12421  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12422  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12423  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12424  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
12425  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
12426  MMIT++;
12427  MMIT++;
12428  MMIT++;
12429  MMIT++;
12430  }
12431  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
12432  {
12433  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12434  { // 0 & 1 constitute the bidirectional PrefDir
12435  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12436  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12437  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12438  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12439  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
12440  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
12441  MMIT++;
12442  MMIT++;
12443  MMIT++;
12444  }
12445  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
12446  { // 0 & 2 constitute the bidirectional PrefDir
12447  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12448  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12449  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12450  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12451  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12452  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12453  MMIT++;
12454  MMIT++;
12455  MMIT++;
12456  }
12457  else
12458  { // 1 & 2 constitute the bidirectional PrefDir
12459  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12460  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12461  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12462  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12463  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12464  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12465  MMIT++;
12466  MMIT++;
12467  MMIT++;
12468  }
12469  }
12470  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
12471  {
12472  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12473  { // 0 & 1 constitute the bidirectional PrefDir
12474  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12475  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12476  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12477  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12478  MMIT++;
12479  MMIT++;
12480  }
12481  else
12482  { // 2 unidirectional PrefDirs
12483  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12484  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12485  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12486  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12487  MMIT++;
12488  MMIT++;
12489  }
12490  }
12491  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
12492  {
12493  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12494  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12495  MMIT++;
12496  }
12497  }
12498  Utilities->CallLogPop(1565);
12499 }
12500 
12501 // ---------------------------------------------------------------------------
12502 
12503 bool TOnePrefDir::PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos) // added at v1.2.0
12504 /*
12505  Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entry position, not points, crossovers,
12506  level crossing, signals with wrong direction set, or buffers.
12507 */
12508 {
12509  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteElementValid");
12510  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12511  bool FoundFlag;
12513  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
12514 
12515  if((ElementIn.TrackType == Points) || (ElementIn.TrackType == Crossover) || (ElementIn.TrackType == Buffers) || (Track->IsLCAtHV(49, ElementIn.HLoc,
12516  ElementIn.VLoc)))
12517  {
12518  Utilities->CallLogPop(1982);
12519  return false;
12520  }
12521  if((ElementIn.TrackType == SignalPost) && (ElementIn.Config[EntryPos] == Signal)) // Signal is at exit end
12522  {
12523  Utilities->CallLogPop(1983);
12524  return false;
12525  }
12526  if((ElementIn.TrackType == SignalPost) && (ElementIn.SigAspect == TTrackElement::GroundSignal))
12527  {
12528  Utilities->CallLogPop(1995);
12529  return false;
12530  }
12531 // Now check that there is only a single prefdir set
12532  GetVectorPositionsFromPrefDir4MultiMap(8, ElementIn.HLoc, ElementIn.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12533 // always found in order, any missing have PrefDirPosx == -1
12534  if(PrefDirPos0 > -1)
12535  PrefDirElement0 = GetFixedPrefDirElementAt(213, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
12536  if(PrefDirPos1 > -1)
12537  PrefDirElement1 = GetFixedPrefDirElementAt(214, PrefDirPos1);
12538  if(PrefDirPos2 > -1)
12539  PrefDirElement2 = GetFixedPrefDirElementAt(215, PrefDirPos2);
12540  if(PrefDirPos3 > -1)
12541  PrefDirElement3 = GetFixedPrefDirElementAt(216, PrefDirPos3);
12542 
12543  if(PrefDirPos3 > -1) // 4 found, all bidirectional
12544  {
12545  Utilities->CallLogPop(1984);
12546  return false;
12547  }
12548  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
12549  {
12550  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos) || (PrefDirElement2.XLinkPos == EntryPos))
12551  {
12552  Utilities->CallLogPop(1985);
12553  return false;
12554  }
12555  else
12556  {
12557  Utilities->CallLogPop(1986);
12558  return true;
12559  }
12560  }
12561  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
12562  {
12563  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos))
12564  {
12565  Utilities->CallLogPop(1987);
12566  return false;
12567  }
12568  else
12569  {
12570  Utilities->CallLogPop(1988);
12571  return true;
12572  }
12573  }
12574  else if(PrefDirPos0 > -1) // one found, make sure in correct direction
12575  {
12576  if(PrefDirElement0.XLinkPos == EntryPos)
12577  {
12578  Utilities->CallLogPop(1989);
12579  return false;
12580  }
12581  else
12582  {
12583  Utilities->CallLogPop(1990);
12584  return true;
12585  }
12586  }
12587  else
12588  {
12589  Utilities->CallLogPop(1991);
12590  return false; // none found
12591  }
12592 }
12593 
12594 // ---------------------------------------------------------------------------
12595 
12597 {
12598 /* //Added at v2.1.0
12599  Called by GetStartAndEndPrefDirElements, which in turn is called by PresetAutoSigRoutesButtonClick. Checks for a diagonal link in
12600  the autosigsroute being fouled by an adjacent track with a corresponding link that meets at the diagonal link, and if it is it
12601  returns true and prevents the route being set. Note that adjacent track consisting of buffers, gaps and continuations at the
12602  diagonal link are also excluded though they need not be, but it makes the check code simpler and such adjacent track is untidy
12603  and can be modelled better anyway.
12604 
12605  Enter with PrefDirElement whose XLink is to be checked for track that fouls a diagonal.
12606  If XLink is anything but 1,3,7 or 9 return false - no fouling as not a diagonal.
12607  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
12608  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
12609  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
12610  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
12611 */
12612  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteDiagonalFouledByTrack," + ElementIn.HLoc + "," +
12613  ElementIn.VLoc + "," + XLink);
12614  int TrackVecPos;
12615  bool TrackFoundFlag;
12616  TTrackElement TempTrackElement;
12617 
12618  if((XLink == 2) || (XLink == 4) || (XLink == 6) || (XLink == 8))
12619  {
12620  Utilities->CallLogPop(2047);
12621  return false;
12622  }
12623 
12624 // for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
12625  if(XLink == 1)
12626  {
12627  TrackVecPos = Track->GetVectorPositionFromTrackMap(48, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
12628  if(TrackFoundFlag)
12629  {
12630  TempTrackElement = Track->TrackElementAt(898, TrackVecPos);
12631  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
12632  {
12633  Utilities->CallLogPop(2048);
12634  return true;
12635  }
12636  }
12637  TrackVecPos = Track->GetVectorPositionFromTrackMap(49, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
12638  if(TrackFoundFlag)
12639  {
12640  TempTrackElement = Track->TrackElementAt(899, TrackVecPos);
12641  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
12642  {
12643  Utilities->CallLogPop(2049);
12644  return true;
12645  }
12646  }
12647  }
12648 
12649 // for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
12650  if(XLink == 3)
12651  {
12652  TrackVecPos = Track->GetVectorPositionFromTrackMap(50, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
12653  if(TrackFoundFlag)
12654  {
12655  TempTrackElement = Track->TrackElementAt(900, TrackVecPos);
12656  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
12657  {
12658  Utilities->CallLogPop(2050);
12659  return true;
12660  }
12661  }
12662  TrackVecPos = Track->GetVectorPositionFromTrackMap(51, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
12663  if(TrackFoundFlag)
12664  {
12665  TempTrackElement = Track->TrackElementAt(901, TrackVecPos);
12666  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
12667  {
12668  Utilities->CallLogPop(2051);
12669  return true;
12670  }
12671  }
12672  }
12673 
12674 // for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
12675  if(XLink == 7)
12676  {
12677  TrackVecPos = Track->GetVectorPositionFromTrackMap(52, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
12678  if(TrackFoundFlag)
12679  {
12680  TempTrackElement = Track->TrackElementAt(902, TrackVecPos);
12681  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
12682  {
12683  Utilities->CallLogPop(2052);
12684  return true;
12685  }
12686  }
12687  TrackVecPos = Track->GetVectorPositionFromTrackMap(53, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
12688  if(TrackFoundFlag)
12689  {
12690  TempTrackElement = Track->TrackElementAt(903, TrackVecPos);
12691  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
12692  {
12693  Utilities->CallLogPop(2053);
12694  return true;
12695  }
12696  }
12697  }
12698 
12699 // for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
12700  if(XLink == 9)
12701  {
12702  TrackVecPos = Track->GetVectorPositionFromTrackMap(54, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
12703  if(TrackFoundFlag)
12704  {
12705  TempTrackElement = Track->TrackElementAt(904, TrackVecPos);
12706  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
12707  {
12708  Utilities->CallLogPop(2054);
12709  return true;
12710  }
12711  }
12712  TrackVecPos = Track->GetVectorPositionFromTrackMap(55, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
12713  if(TrackFoundFlag)
12714  {
12715  TempTrackElement = Track->TrackElementAt(905, TrackVecPos);
12716  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
12717  {
12718  Utilities->CallLogPop(2055);
12719  return true;
12720  }
12721  }
12722  }
12723  Utilities->CallLogPop(2056);
12724  return false;
12725 }
12726 
12727 // ---------------------------------------------------------------------------
12728 
12729 bool TOnePrefDir::GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
12730 {
12731 /* Called by PresetAutoSigRoutesButtonClick in the Interface unit. LastIteratorValue gives the position in EveryPrefDir to start from. Search
12732  EveryPrefDir for continuations (facing inwards wrt pref dir) or non-ground signals in single direction pref dirs, and when find one track forwards
12733  to the next non-ground signal or continuation. If, before finding a valid signal or continuation find points, crossover, level crossing or buffers,
12734  or an element that is already in a route, stop tracking and continue with the search for another valid continuation or signal. When find a suitable
12735  pair, return the elements in StartElement and EndElement, and also the LastIteratorValue ready for the next call.
12736 */
12737  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetStartAndEndPrefDirElements," + AnsiString(LastIteratorValue));
12739  bool FoundFlag, ContFlag, FoundElements = false;
12740  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12741  TPrefDirElement NextElement;
12742 
12743  for(PDVIt = (PrefDirVector.begin() + LastIteratorValue); PDVIt < PrefDirVector.end(); PDVIt++)
12744  {
12745  LastIteratorValue++;
12746  ContFlag = false;
12747  if((PDVIt->TrackType != SignalPost) && (PDVIt->TrackType != Continuation))
12748  continue;
12749  if((PDVIt->TrackType == SignalPost) && (PDVIt->SigAspect == TTrackElement::GroundSignal))
12750  continue;
12751 // if(AllRoutes::TrackIsInARoute(, PDVIt->TrackVectorPosition, PDVIt->EntryPos) continue; //already in a route - no, don't check start position as if a signal might well be at end of an existing route
12752  // found a potential route start point
12753  if(PresetAutoRouteDiagonalFouledByTrack(0, *PDVIt, PDVIt->XLink)) // Added at v2.1.0
12754  {
12755  continue;
12756  }
12757  if(PresetAutoRouteElementValid(0, *PDVIt, PDVIt->ELinkPos))
12758  {
12759  // check if continuation either in a route or with prefdir facing 'End' (OK if find it as EndElement, but not as StartElement)
12760  if(PDVIt->TrackType == Continuation)
12761  {
12762  if(AllRoutes->TrackIsInARoute(18, PDVIt->TrackVectorPosition, PDVIt->ELinkPos))
12763  {
12764  continue;
12765  }
12766  if(PDVIt->XLinkPos == 0) // position 0 is the continuation
12767  {
12768  continue;
12769  }
12770  }
12771  StartElement = *PDVIt;
12772 // in Glenn Mitchell's error log (14/04/13) the offending signal start position was 4680, problem was it linked to a point with pref dirs set on through track but signal linked to
12773  // diverging track on which there was no pref dir. See below for 2 required changes.
12774  }
12775  else
12776  {
12777  continue;
12778  }
12779  // now track along until find a signal or continuation, checking validity for each element
12780  int NextTrackVectorPosition = PDVIt->Conn[PDVIt->GetXLinkPos()];
12781  GetVectorPositionsFromPrefDir4MultiMap(9, Track->TrackElementAt(878, NextTrackVectorPosition).HLoc,
12782  Track->TrackElementAt(879, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12783  if(PrefDirPos0 == -1) // no continuing prefdir
12784  {
12785  continue;
12786  }
12787  bool NextElementFoundFlag = false;
12788  if(GetFixedPrefDirElementAt(217, PrefDirPos0).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
12789  {
12790  NextElement = GetFixedPrefDirElementAt(218, PrefDirPos0);
12791  NextElementFoundFlag = true;
12792  }
12793  if(PrefDirPos1 > -1)
12794  {
12795  if(GetFixedPrefDirElementAt(219, PrefDirPos1).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
12796  {
12797  NextElement = GetFixedPrefDirElementAt(220, PrefDirPos1);
12798  NextElementFoundFlag = true;
12799  }
12800  }
12801  if(PrefDirPos2 > -1)
12802  {
12803  if(GetFixedPrefDirElementAt(221, PrefDirPos2).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
12804  {
12805  NextElement = GetFixedPrefDirElementAt(222, PrefDirPos2);
12806  NextElementFoundFlag = true;
12807  }
12808  }
12809  if(PrefDirPos3 > -1)
12810  {
12811  if(GetFixedPrefDirElementAt(223, PrefDirPos3).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
12812  {
12813  NextElement = GetFixedPrefDirElementAt(224, PrefDirPos3);
12814  NextElementFoundFlag = true;
12815  }
12816  }
12817  if(!NextElementFoundFlag)
12818  {
12819  continue; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
12820 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (1)")); //[GM error 14/04/13] for next release change this to 'continue;' to quit from trying to find the auto route (don't need to throw an exception)
12821  }
12822  while(true)
12823  {
12824  // check validity
12825  if(PresetAutoRouteDiagonalFouledByTrack(1, NextElement, NextElement.XLink)) // Added at v2.1.0
12826  {
12827  ContFlag = true;
12828  break;
12829  }
12830  if(!PresetAutoRouteElementValid(1, NextElement, NextElement.ELinkPos))
12831  {
12832  ContFlag = true;
12833  break;
12834  }
12835  // check if in a route, providing not a signal, as a signal might be at the start of a route
12836  if(NextElement.TrackType != SignalPost)
12837  {
12838  if(AllRoutes->TrackIsInARoute(17, NextElement.TrackVectorPosition, NextElement.ELinkPos))
12839  {
12840  ContFlag = true;
12841  break;
12842  }
12843  }
12844  if((NextElement.TrackType == SignalPost) || (NextElement.TrackType == Continuation))
12845  // can't be a gound signal as would have failed the validity test
12846  {
12847  EndElement = NextElement;
12848  break;
12849  }
12850  // get the next element in the sequence
12851  NextTrackVectorPosition = NextElement.Conn[NextElement.GetXLinkPos()];
12852  GetVectorPositionsFromPrefDir4MultiMap(10, Track->TrackElementAt(880, NextTrackVectorPosition).HLoc,
12853  Track->TrackElementAt(881, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12854  if(PrefDirPos0 == -1) // no continuing prefdir
12855  {
12856  ContFlag = true;
12857  break;
12858  }
12859  if(GetFixedPrefDirElementAt(225, PrefDirPos0).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
12860  {
12861  NextElement = GetFixedPrefDirElementAt(226, PrefDirPos0);
12862  continue;
12863  }
12864  if(PrefDirPos1 > -1)
12865  {
12866  if(GetFixedPrefDirElementAt(227, PrefDirPos1).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
12867  {
12868  NextElement = GetFixedPrefDirElementAt(228, PrefDirPos1);
12869  continue;
12870  }
12871  }
12872  if(PrefDirPos2 > -1)
12873  {
12874  if(GetFixedPrefDirElementAt(229, PrefDirPos2).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
12875  {
12876  NextElement = GetFixedPrefDirElementAt(230, PrefDirPos2);
12877  continue;
12878  }
12879  }
12880  if(PrefDirPos3 > -1)
12881  {
12882  if(GetFixedPrefDirElementAt(231, PrefDirPos3).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
12883  {
12884  NextElement = GetFixedPrefDirElementAt(232, PrefDirPos3);
12885  continue;
12886  }
12887  }
12888  // had exception thrown here if NextElement not found, but could be a bridge where opposite track PrefDir set, in which case won't find it
12889  // found with Jonathan Kwok's DLR railway (17/11/12) where undertrack PrefDir not set just west of Poplar. Hence first test if element is a bridge
12890  // and if so set ContFlag to true & break (same as not finding PrefDir element at all). Modified at version 1.3.1
12891  // note that it's not NextElement that is to be examined but NextTrackVectorPosition, which can be found easily by using PrefDirPos0 (there will be a
12892  // PrefDirPos0 or would have exited earlier, and it doesn't matter that PrefDirPos0 isn't on the route in question because only the TrackType is needed)
12893  if(GetFixedPrefDirElementAt(243, PrefDirPos0).TrackType == Bridge)
12894  {
12895  ContFlag = true;
12896  break;
12897  }
12898  else
12899  {
12900  ContFlag = true; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
12901  // could drop the bridge test but keep it to show the change history
12902  break;
12903 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (2)")); //[GM error 14/04/13] for next release set ContFlag to true & break' to quit from trying to find the auto route (don't need to throw an exception)
12904  }
12905  }
12906  if(ContFlag)
12907  continue;
12908  // else have start and end elements set & all elements valid, so set up the route segment
12909  FoundElements = true;
12910  break;
12911  }
12912  if(FoundElements)
12913  {
12914  Utilities->CallLogPop(1992);
12915  return true;
12916  }
12917  else
12918  {
12919  Utilities->CallLogPop(1993);
12920  return false;
12921  }
12922 }
12923 
12924 // ---------------------------------------------------------------------------
12925 // TOneRoute
12926 // ---------------------------------------------------------------------------
12927 
12928 bool TOneRoute::GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, bool AutoSigsFlag)
12929 {
12930 /* General:
12931  The basis of all these route setting functions, preferred and non-preferred, is that a SearchVector is set up
12932  containing all the new elements to form the route. When complete, the SearchVector is converted into route
12933  elements, either as a new route, or an extension to an existing route. The AutoSigs flag determines whether the
12934  route will use automatic signals or not.
12935  For preferred and non-preferred routes, all new elements (as opposed to those already in existing routes) go
12936  into the SearchVector. For non-preferred routes, trackelements are selected that are not necessarily PrefDir
12937  elements, so additional work is needed to complete all their members before they are ready for conversion into
12938  a route - see SetRemainingSearchVectorValues. The call order is GetStart....; GetNext...,
12939  which includes the Search... function; [SetRemainingSearchVectorValues for non-preferred routes only], then
12940  ConvertAndAdd.......
12941 
12942  Note that originally intended to allow preferred routes without consecutive signals, hence ConsecSignalsRoute flag.
12943  Later decided to enforce ConsecSignalsRoute for preferred routes, but left original code as was.
12944 
12945  Specific:
12946 
12947  Function returns true for a valid start element, false, with a message, if not.
12948  ClearRoute to empty both PrefDirVector & SearchVector
12949  Check selection matches a TrackElement & ensure a signal/buffers/continuation if using ConsecSignals,
12950  else disallow points, bridge or crossover.
12951  Disallow if train on element.
12952 
12953  Set default values for parameters that are retained in AllRoutes:-
12954  StartSelectionRouteID = route that selection starts in or adjacent to end of;
12955  StartRoutePosition = trackvectornumber of the element to be used as the start of the route;
12956  StartElement1 = the 1st or only TPrefDirElement of the route start element
12957  StartElement2 = the 2nd (if exists) TPrefDirElement of the start element (can be a max of 2 PrefDirs for
12958  a given selection that isn't points, bridge or crossover;
12959 
12960  Check selection corresponds to at least 1 PrefDir element in EveryPrefDir & set StartElement1 & possibly also 2. If
12961  signal/buffers/continuation for ConsecSignalsRoute, or buffers/continuation for not ConsecSignalsRoute,
12962  ensure the PrefDir corresponds to the direction of the signal or away from the buffers/continuation.
12963  Check if in an existing route. Disallow if start anywhere except at end of the route, if the route end is an 'End'
12964  configuration (nowhere to go), and if the end of the route links forwards into another route.
12965  If these tests passed set StartSelectionRouteID, StartElement1 and StartRoutePosition to correspond to the route end element
12966  and blank StartElement2 (only want to use the route element), then return true.
12967  Check also that doesn't lie in >1 route & give error message if so - should never happen.
12968  Check if adjacent to start or end of an existing route & disallow.
12969  The start element (with AutoSignals member set as AutoSigs flag) is stored in SearchVector, unless an existing route element is to
12970  be used as the start element.
12971 */
12972  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPreferredRouteStartElement," + AnsiString(HLoc) + "," +
12973  AnsiString(VLoc) + "," + AnsiString((short)AutoSigsFlag));
12974  ClearRoute();
12975  int TrackVectorPosition;
12976  TTrackElement TrackElement;
12977  TPrefDirElement FirstElement, LastElement;
12978 
12979  if(!(Track->FindNonPlatformMatch(7, HLoc, VLoc, TrackVectorPosition, TrackElement)))
12980  {
12981  Utilities->CallLogPop(199);
12982  return false;
12983  }
12984  if(ConsecSignalsRoute)
12985  {
12986  if(AutoSigsFlag && (TrackElement.TrackType == Buffers)) // added at v1.2.0
12987  {
12988  TrainController->StopTTClockMessage(80, "Can't create an automatic signal route from buffers");
12989  Utilities->CallLogPop(1996);
12990  return false;
12991  }
12992  else if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
12993  {
12994  TrainController->StopTTClockMessage(7, "Must select a valid signal, buffers or continuation");
12995  Utilities->CallLogPop(200);
12996  return false;
12997  }
12998  }
12999  else
13000  {
13001  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
13002  {
13003  TrainController->StopTTClockMessage(8, "Can't select points, bridge or crossover when route building");
13004 // makes later adjacent route checks too complicated
13005  Utilities->CallLogPop(201);
13006  return false;
13007  }
13008  }
13009 
13010  if(Track->IsLCAtHV(18, HLoc, VLoc))
13011  {
13012  TrainController->StopTTClockMessage(73, "Can't start a route on a level crossing");
13013  Utilities->CallLogPop(1909);
13014  return false;
13015  }
13016 
13017 // check if selected a train & disallow if so
13018  if(TrackElement.TrainIDOnElement > -1)
13019  {
13020  TrainController->StopTTClockMessage(9, "Can't start a route on a train");
13021  Utilities->CallLogPop(202);
13022  return false;
13023  }
13024 
13025 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
13026  TPrefDirElement PrefDirElement;
13027  int LockedVectorNumber;
13028 
13029  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(1, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
13030  {
13031  TrainController->StopTTClockMessage(10, "Can't start a route on a locked route");
13032  Utilities->CallLogPop(203);
13033  return false;
13034  }
13035  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(2, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
13036  {
13037  TrainController->StopTTClockMessage(11, "Can't start a route on a locked route");
13038  Utilities->CallLogPop(204);
13039  return false;
13040  }
13041 
13043  StartRoutePosition = TrackVectorPosition; // actual route start - may be element following StartRouteSelectPosition if select a
13044 // signal in an autosig route & follow with a non-autosig route
13045 
13046  TPrefDirElement BlankElement;
13047 
13048  StartElement1 = BlankElement;
13049  StartElement2 = BlankElement;
13050 // check it's in a PrefDir (could be 2 entries for two possible PrefDirs, can only select single track elements so can't have more than 2 PrefDirs)
13051  bool InPrefDirFlag = false;
13052 
13053  bool FoundFlag;
13054  int PrefDirPos0 = -1;
13055  int PrefDirPos1 = -1;
13056  int PrefDirPos2 = -1;
13057  int PrefDirPos3 = -1;
13058 
13060  Track->TrackElementAt(85, StartRoutePosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13061  int PrefDirVecPos[4] =
13062  {PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3};
13063 
13064  for(int x = 0; x < 4; x++)
13065  {
13066  int b = PrefDirVecPos[x];
13067  if(b > -1)
13068  {
13069  if(ConsecSignalsRoute)
13070  {
13071  // only allow the appropriate exit route to be searched
13072  if(((TrackElement.TrackType == SignalPost) && (EveryPrefDir->GetFixedPrefDirElementAt(15, b).Config[EveryPrefDir->GetFixedPrefDirElementAt(16,
13073  b).XLinkPos] == Signal)) || ((TrackElement.TrackType == Buffers) && (EveryPrefDir->GetFixedPrefDirElementAt(17,
13074  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(18, b).XLinkPos] == Connection)) ||
13075  ((TrackElement.TrackType == Continuation) && (EveryPrefDir->GetFixedPrefDirElementAt(19,
13076  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(20, b).XLinkPos] == Connection)))
13077  {
13078  InPrefDirFlag = true;
13079  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(21, b);
13080  if(AutoSigsFlag)
13081  {
13082  StartElement1.AutoSignals = true;
13083  }
13085  StartElement2 = BlankElement;
13086  }
13087  }
13088  else
13089  {
13090  // only allow the appropriate exit route to be searched
13091  // AutoSignals & ConsecSignals stay false for not ConsecSignalsRoute
13092  if(((TrackElement.TrackType == Buffers) && (EveryPrefDir->GetFixedPrefDirElementAt(22, b).Config[EveryPrefDir->GetFixedPrefDirElementAt(23,
13093  b).XLinkPos] == Connection)) || ((TrackElement.TrackType == Continuation) && (EveryPrefDir->GetFixedPrefDirElementAt(24,
13094  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(25, b).XLinkPos] == Connection)))
13095  {
13096  InPrefDirFlag = true;
13097  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(26, b);
13098  StartElement2 = BlankElement;
13099  }
13100  else if((TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
13101  {
13102  InPrefDirFlag = true;
13104  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(27, b);
13105  else
13106  StartElement2 = EveryPrefDir->GetFixedPrefDirElementAt(28, b);
13107  }
13108  }
13109  }
13110  }
13111 
13112  if(!InPrefDirFlag)
13113  {
13115  "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
13116  Utilities->CallLogPop(205);
13117  return false;
13118  }
13119 
13120 // look for exact match in a route first - can't be a bridge so can use a simple 'find'
13122  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(14, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
13123 
13124  if(DummyPair.first > -1) // if DummyPair exists then an error as start element can only be in one route (bridges not allowed)
13125  {
13126  throw Exception("Selection in two routes - should never happen!");
13127  }
13128 
13129  if(RoutePair.first > -1) // no need to examine DummyPair as start element can only be in one route (bridges not allowed)
13130  {
13131  if(RoutePair.second != AllRoutes->GetFixedRouteAt(1, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
13132  {
13133  TrainController->StopTTClockMessage(13, "Can't start a route within or at the start of an existing route");
13134  Utilities->CallLogPop(206);
13135  return false;
13136  }
13137  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(2, RoutePair.first).GetFixedPrefDirElementAt(29, RoutePair.second);
13138  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
13139  {
13140  TrainController->StopTTClockMessage(14, "No forward connection from this position");
13141  Utilities->CallLogPop(207);
13142  return false;
13143  }
13144  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(9, RouteElement.Conn[RouteElement.XLinkPos],
13145  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
13146  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
13147  {
13148  TrainController->StopTTClockMessage(15, "Can't start a route at an element that links forward into an existing route");
13149  Utilities->CallLogPop(208);
13150  return false;
13151  }
13152  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(158, RoutePair.first).RouteID);
13154  AllRoutes->GetFixedRouteAt(4, RoutePair.first).PrefDirSize() - 1); // last element
13155  if(AutoSigsFlag)
13156  {
13157  StartElement1.AutoSignals = true;
13158  }
13159  if(ConsecSignalsRoute)
13160  {
13162  }
13163  StartElement2 = BlankElement; // only use the route element
13165  Utilities->CallLogPop(209);
13166  return true; // all retained values (StartElement1 & maybe 2; StartRoutePosition) set
13167  }
13168 
13169  else // no route started
13170  {
13171 // check if selected position is adjacent to start or end of an existing route and disallow
13172  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
13173  {
13174  FirstElement = AllRoutes->GetFixedRouteAt(5, a).GetFixedPrefDirElementAt(31, 0);
13175  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
13176  {
13177  TrainController->StopTTClockMessage(16, "Can't make selection adjacent to start of another route");
13178  Utilities->CallLogPop(210);
13179  return false;
13180  }
13181  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
13182  {
13183  TrainController->StopTTClockMessage(17, "Can't make selection adjacent to start of another route");
13184  Utilities->CallLogPop(211);
13185  return false;
13186  }
13187  }
13188 
13189 // check if it's adjacent to end of an an existing route,
13190  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
13191  {
13193  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
13194  {
13195  TrainController->StopTTClockMessage(18, "Can't start a route adjacent to the end of an existing route");
13196  Utilities->CallLogPop(212);
13197  return false;
13198  }
13199  }
13200  SearchVector.push_back(StartElement1);
13201  Utilities->CallLogPop(213);
13202  return true;
13203  }
13204 }
13205 
13206 // ---------------------------------------------------------------------------
13207 
13208 bool TOneRoute::GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, bool AutoSigsFlag,
13209  IDInt &ReqPosRouteID, bool &PointsChanged)
13210 
13211 /*
13212  [Note this was written when it was intended to have routes confined to preferred direction elements but with a choice of whether
13213  they had to run from signal to signal (bool ConsecSignalsRoute true), or not (bool ConsecSignalsRoute false), as well as using
13214  automatic signals or not. Since then it was decided only to allow these routes to run from signal to signal, so ConsecSignalsRoute
13215  is always true when this routine is called. The routine could be made much simpler, but has been left as is because it works (at
13216  least it has done so far), and it allows the original option to be used if it ever seems appropriate in the future.]
13217  *
13218  Return true if select valid next element, in which case the route is set & stored. Return false for an invalid next element.
13219  *
13220  Declare integers EndPosition (the position used) and
13221  ReqPosRouteID to hold (when required) the existing route selected, this being set to -1 for not used.
13222  Check if selection is a valid track element, cancel if not, if select original start element or if select buffers
13223  with AutoSigsFlag set - would have no way out and no way to cancel the route with a train at the buffers.
13224  Check correct type of element - signal/buffers/continuation if ConsecSignalsRoute, else not points, bridge or crossover.
13225  Fail if train on element, or if selection not in EveryPrefDir. Otherwise set EndElement1 & possibly also
13226  EndElement2 corresponding to the 2 possible PrefDir elements (similar to StartElement1 & 2 above).
13227  Check if selection is first element in an existing route & if so set ReqPosRouteID, EndElement1, and set EndElement2 to
13228  blank as can only be one route at that element (can't select bridges). Fail if in a route & not at start, or at start but route
13229  linked forward to another route.
13230  Check & fail if adjacent to start or end of an existing route, or if select the route that selected at start (though earlier check
13231  for same position as start should cover this)
13232  *
13233  If there's a StartSelectionRouteID then StartElement1 will be set to the last entry in the selected route so use
13234  SearchForPreferredRoute to search for the selected end element from this start element. If succeed then set the search vector
13235  graphics using SetRouteSearchVectorGraphics(AutoSigsFlag) & return true, for Interface to handle the flashing & time delay. After the
13236  delay completes the Interface flasher calls ConvertAndAddPreferredRouteSearchVector to add the new route to the AllRoutesVectorPtr.
13237  If the search fails the return false.
13238  If there isn't a StartSelectionRouteID then the starting element is not already in a route, so it will have been stored
13239  in the SearchVector to ensure it's entered as part of the new route.
13240  First check whether the selected element (either EndElement1 or 2) is adjacent to the starting position and if so set the route to go
13241  directly to it (as opposed to going round a long loop to get to it just because that XLinkPos happens to be chosen first. If not
13242  adjacent then first search on EndElement1, and if fail search on EndElement2 providing it's set. If succeed set
13243  set the search vector graphics as above and return. If reach end of function then have failed to find a valid element,
13244  so return false, with an appropriate message if ConsecSignalsRoute set.
13245 */
13246 
13247 {
13248  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPreferredRouteElement," + AnsiString(HLoc) + "," +
13249  AnsiString(VLoc) + "," + AnsiString((short)AutoSigsFlag));
13250  int EndPosition; // the position selected
13251 
13252  Track->LCFoundInAutoSigsRoute = false;
13254  TotalSearchCount = 0;
13255  ReqPosRouteID = IDInt(-1); // default value for not used
13256  TTrackElement TrackElement;
13257  TPrefDirElement EndElement1, EndElement2, BlankElement; // all blank to begin with, can only have max of 2 PrefDirs on a
13258 
13259  // given element as can't select 2-track elements
13260  if(!(Track->FindNonPlatformMatch(8, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
13261  {
13262  Utilities->CallLogPop(214);
13263  return false;
13264  }
13265 
13266  if(Track->IsLCAtHV(19, HLoc, VLoc))
13267  {
13268  TrainController->StopTTClockMessage(72, "Can't end a route on a level crossing");
13269  Utilities->CallLogPop(1908);
13270  return false;
13271  }
13272 
13273 // cancel selection if on original start element
13274  if(EndPosition == StartRoutePosition)
13275  {
13276  Utilities->CallLogPop(215);
13277  return false;
13278  }
13279  if(AutoSigsFlag)
13280  {
13281  if(TrackElement.TrackType == Buffers)
13282  {
13283  TrainController->StopTTClockMessage(19, "Can't create an automatic signal route into buffers");
13284  Utilities->CallLogPop(216);
13285  return false;
13286  }
13287  }
13288  if(ConsecSignalsRoute)
13289  {
13290  if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
13291  {
13292  TrainController->StopTTClockMessage(20, "Must select a valid signal, buffers or continuation");
13293  Utilities->CallLogPop(217);
13294  return false;
13295  }
13296  }
13297  else // not needed now can't have preferred non-consec signals routes, but leave in
13298  {
13299  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
13300  {
13301  TrainController->StopTTClockMessage(21, "Can't select points, bridge or crossover when building a route");
13302 // makes later adjacent route checks too complicated
13303  Utilities->CallLogPop(218);
13304  return false;
13305  }
13306  }
13307 
13308 // check if train on element
13309  if(TrackElement.TrainIDOnElement > -1)
13310  {
13311  TrainController->StopTTClockMessage(22, "Can't end a route on a train");
13312  Utilities->CallLogPop(219);
13313  return false;
13314  }
13315 
13316 // disallow if not in EveryPrefDir & set EndElement(s)
13317  bool InPrefDirFlag = false;
13318 
13319  bool FoundFlag;
13320  int PrefDirPos0 = -1;
13321  int PrefDirPos1 = -1;
13322  int PrefDirPos2 = -1;
13323  int PrefDirPos3 = -1;
13324 
13325  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(4, Track->TrackElementAt(86, EndPosition).HLoc, Track->TrackElementAt(87, EndPosition).VLoc, FoundFlag,
13326  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13327  int PrefDirVecPos[4] =
13328  {PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3};
13329 
13330  for(int x = 0; x < 4; x++)
13331  {
13332  int b = PrefDirVecPos[x];
13333  if(b > -1)
13334  {
13335  InPrefDirFlag = true;
13336  if(EndElement1.TrackVectorPosition == -1)
13337  EndElement1 = EveryPrefDir->GetFixedPrefDirElementAt(33, b);
13338  else
13339  EndElement2 = EveryPrefDir->GetFixedPrefDirElementAt(34, b);
13340  }
13341  }
13342  if(!InPrefDirFlag)
13343  {
13345  "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
13346  Utilities->CallLogPop(220);
13347  return false;
13348  }
13349 
13350 // check if in an existing route - can't be a bridge so can use a simple 'find'
13351 // bool InRoute = false;
13353  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(15, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
13354 
13355  if(RoutePair.first > -1)
13356  {
13357  if(RoutePair.second != 0) // not first element in existing route so no good
13358  {
13359  TrainController->StopTTClockMessage(24, "Can't end a route within or at the end of an existing route");
13360  Utilities->CallLogPop(221);
13361  return false;
13362  }
13363  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(8, RoutePair.first).GetFixedPrefDirElementAt(35, RoutePair.second);
13364 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
13365  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(10, RouteElement.Conn[RouteElement.ELinkPos],
13366  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
13367  // discovered when timetable building for Joshua Coupe's railway. Also affects non-preferred routes - see below
13368  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
13369  {
13370  TrainController->StopTTClockMessage(25, "Can't start a route within or at the end of an existing route");
13371  Utilities->CallLogPop(222);
13372  return false;
13373  }
13374  EndElement1 = RouteElement;
13375  EndElement2 = BlankElement; // only need the route element
13376  EndPosition = EndElement1.TrackVectorPosition;
13377  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(160, RoutePair.first).RouteID);
13378  }
13379 
13380 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
13381 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
13382 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
13383 
13384  if(EndElement1.HLoc >= StartElement1.HLoc)
13385  {
13387  SearchLimitHighH = EndElement1.HLoc + 15;
13388  }
13389  else
13390  {
13391  SearchLimitLowH = EndElement1.HLoc - 15;
13393  }
13394 
13395  if(EndElement1.VLoc >= StartElement1.VLoc)
13396  {
13398  SearchLimitHighV = EndElement1.VLoc + 15;
13399  }
13400  else
13401  {
13402  SearchLimitLowV = EndElement1.VLoc - 15;
13404  }
13405 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
13406  check & TotalSearchCounts check
13407  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
13408  {
13409  TrainController->StopTTClockMessage(65, "Unable to reach the selected element - too far ahead");
13410  Utilities->CallLogPop(1693);
13411  return false;
13412  }
13413 */
13414 // check if adjacent to start and disallow
13415  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
13416  {
13418  int AdjLinkPos = AllRoutes->GetFixedRouteAt(218, a).GetFixedPrefDirElementAt(244, 0).ELinkPos; // added at v1.3.1
13419 // if((EndElement1.Config[EndElement1.XLinkPos] != End) &&
13420 // (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition))
13421  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
13422  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
13423  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos))
13424  {
13425  TrainController->StopTTClockMessage(26, "Can't end a route adjacent to the start of an existing route");
13426  Utilities->CallLogPop(223);
13427  return false;
13428  }
13429 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
13430 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition))
13431  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
13432  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
13433  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos))
13434  {
13435  TrainController->StopTTClockMessage(27, "Can't end a route adjacent to the start of an existing route");
13436  Utilities->CallLogPop(224);
13437  return false;
13438  }
13439 
13440 // check if adjacent to end of a route & disallow
13442  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition))
13443  {
13444  TrainController->StopTTClockMessage(28, "Can't end a route adjacent to the end of an existing route");
13445  Utilities->CallLogPop(225);
13446  return false;
13447  }
13448  }
13449 
13450 // check for same route as start element
13452  {
13453  TrainController->StopTTClockMessage(29, "Can't select same route as started in");
13454  Utilities->CallLogPop(226);
13455  return false;
13456  }
13457 
13458 // check for a looping route
13459  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
13460  {
13462  {
13463  TrainController->StopTTClockMessage(69, "Can't create a route that loops back on itself");
13464  Utilities->CallLogPop(1844);
13465  return false;
13466  }
13467  }
13468 
13469 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
13470 // so search from this element. No need to add StartElement to the SearchVector since it already exists in a route
13471 // and don't want to add it again
13472  if(StartSelectionRouteID > -1)
13473  {
13474  if(SearchForPreferredRoute(0, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
13475  AutoSigsFlag))
13476  {
13477  SetRouteSearchVectorGraphics(0, AutoSigsFlag, true); // change graphic colour to the route colour
13478  if(PointsToBeChanged(5))
13479  {
13480  PointsChanged = true;
13481  }
13482  Utilities->CallLogPop(227);
13483  return true;
13484  }
13485  else if(ConsecSignalsRoute && !Track->LCFoundInAutoSigsRouteMessageGiven)
13487  Utilities->CallLogPop(228);
13488  return false;
13489  }
13490  else
13491  {
13492 // Note: StartElement not in an existing route so was added to the searchvector during the earlier function
13493 // First check if selection adjacent to start element and if so use that [can't be as can't have 2 consecutive signals, but leave in]
13494 
13495 // added the XLinkPos checks because of Matt Blades error reported on 28/06/11, where StartElement2 matched EndPosition spuriously
13496 // note that a blank element will have XLinkPos set to -1
13497  if((StartElement1.XLinkPos > -1) && (StartElement1.Conn[StartElement1.XLinkPos] == EndPosition))
13498  {
13499  if(SearchForPreferredRoute(1, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
13500  AutoSigsFlag))
13501  {
13502  SetRouteSearchVectorGraphics(1, AutoSigsFlag, true); // change graphic colour to the route colour
13503  if(PointsToBeChanged(6))
13504  {
13505  PointsChanged = true;
13506  }
13507  Utilities->CallLogPop(229);
13508  return true;
13509  }
13510  else
13511  {
13514  Utilities->CallLogPop(230);
13515  return false;
13516  }
13517  }
13518  else if((StartElement2.XLinkPos > -1) && (StartElement2.Conn[StartElement2.XLinkPos] == EndPosition))
13519  {
13520  if(SearchForPreferredRoute(2, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
13521  AutoSigsFlag))
13522  {
13523  SetRouteSearchVectorGraphics(2, AutoSigsFlag, true); // change graphic colour to the route colour
13524  if(PointsToBeChanged(7))
13525  {
13526  PointsChanged = true;
13527  }
13528  Utilities->CallLogPop(231);
13529  return true;
13530  }
13531  else
13532  {
13535  Utilities->CallLogPop(232);
13536  return false;
13537  }
13538  }
13539 
13540  // now start off in the best direction
13541  int BestPos = Track->FindClosestLinkPosition(0, StartRoutePosition, EndPosition); // can only be 0 or 1
13542  // the following logic is very unstructured as extra bits have been added at different times and I'm reluctant to remove earlier bits in case
13543  // they cover situations that might be overlooked. A full analysis would enable it to be tidied up but it works (so far!) so I'll leave it as it is
13544  // unless new problems are found.
13545  if(StartElement1.XLinkPos == BestPos)
13546  {
13547  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
13548  if(SearchForPreferredRoute(3, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
13549  AutoSigsFlag))
13550  {
13551  SetRouteSearchVectorGraphics(3, AutoSigsFlag, true); // change graphic colour to the route colour
13552  if(PointsToBeChanged(8))
13553  {
13554  PointsChanged = true;
13555  }
13556  Utilities->CallLogPop(233);
13557  return true;
13558  }
13559  else if(StartElement2.TrackVectorPosition > -1)
13560  {
13561  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
13562  if(SearchForPreferredRoute(4, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
13563  AutoSigsFlag))
13564  {
13565  SetRouteSearchVectorGraphics(4, AutoSigsFlag, true); // change graphic colour to the route colour
13566  if(PointsToBeChanged(9))
13567  {
13568  PointsChanged = true;
13569  }
13570  Utilities->CallLogPop(234);
13571  return true;
13572  }
13573  }
13574  }
13575  else if(StartElement2.TrackVectorPosition > -1)
13576  {
13577  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
13578  if(SearchForPreferredRoute(5, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
13579  AutoSigsFlag))
13580  {
13581  SetRouteSearchVectorGraphics(6, AutoSigsFlag, true); // change graphic colour to the route colour
13582  if(PointsToBeChanged(10));
13583  {
13584  PointsChanged = true;
13585  }
13586  Utilities->CallLogPop(1857);
13587  return true;
13588  }
13589  else if(SearchForPreferredRoute(8, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
13590  AutoSigsFlag))
13591  {
13592  SetRouteSearchVectorGraphics(7, AutoSigsFlag, true); // change graphic colour to the route colour
13593  if(PointsToBeChanged(11));
13594  {
13595  PointsChanged = true;
13596  }
13597  Utilities->CallLogPop(1858);
13598  return true;
13599  }
13600  }
13601  else if(StartElement1.XLinkPos == (1 - BestPos))
13602  // added at v0.4d to use StartElement1 again with non-Best direction (may be only one & may not point in right direction
13603  {
13604  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
13605  if(SearchForPreferredRoute(9, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
13606  AutoSigsFlag))
13607  {
13608  SetRouteSearchVectorGraphics(8, AutoSigsFlag, true); // change graphic colour to the route colour
13609  if(PointsToBeChanged(12))
13610  {
13611  PointsChanged = true;
13612  }
13613  Utilities->CallLogPop(1864);
13614  return true;
13615  }
13616  }
13617  }
13620  Utilities->CallLogPop(235);
13621  return false;
13622 }
13623 
13624 // ---------------------------------------------------------------------------
13625 
13626 void TOneRoute::RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
13627 {
13628  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteImageMarker");
13629  if(PrefDirSize() == 0)
13630  {
13631  Utilities->CallLogPop(1704);
13632  return;
13633  }
13634  for(unsigned int x = 0; x < PrefDirSize(); x++)
13635  {
13636  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
13637  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
13638  {
13639  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
13640  TempPrefDirElement.EXGraphicPtr);
13641  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && PrefDirSize() > 1) // Route, no direction if a single element
13642  {
13643  if(x == 0)
13644  {
13645  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
13646  TempPrefDirElement.EntryDirectionGraphicPtr);
13647  }
13648  if(x == (PrefDirSize() - 1))
13649  {
13650  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
13651  TempPrefDirElement.EntryDirectionGraphicPtr);
13652  }
13653  }
13654  }
13655  }
13656 
13657  Utilities->CallLogPop(1705);
13658 }
13659 
13660 // ---------------------------------------------------------------------------
13661 
13662 bool TOneRoute::SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID,
13663  TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, int EndPosition, bool AutoSigsFlag)
13664 
13665 /*
13666  Brief: similar to SearchForPrefDir but with a PrefDirElement instead of a TrackElement & with additional parameters.
13667  PrefDirElement is the starting element from which to search, it is NOT stored in searchvector during this function. If
13668  it's an element that's not already in a route it will have been stored in SearchVector during GetPreferredRouteStartElement.
13669  ReqPosRouteID is used when RequiredPosition is start of an existing route, else it's -1.
13670  Return false if any element (apart from RequiredPosition) is on an existing route.
13671  Return false if not on a PrefDir with same ELink (can't check XLink as may not be set - if it's a leading point).
13672 
13673  Detail: Function is a continuous loop as examine each element on a potential route, exiting only if find
13674  the required position (return true & leave Searchvector as set up) or if fail (erase all SearchVector entries
13675  added during the function so as to leave it exactly as it was on entering, then return false).
13676  It is a recursive function (similar to SearchForPrefDir) to enable all possible point branches to be searched.
13677  A VectorCount is maintained to count elements added to the SearchVector, so that this number can be erased on failure
13678  of any branch. Enter with starting PrefDirElement & XLinkPos for that element, RequiredPosition - the
13679  TrackVectorPosition of the element to be searched for, ReqPosRouteID -
13680  the route number that the searched-for element is the start of if any, and set to -1 if no
13681  such route. A pointer to EveryPrefDir is also passed in since this is not accessible directly from
13682  this unit, together with the ConsecSignalsRoute and AutoSigsFlag flags.
13683  Create 2 TPrefDirElements - PrefDirElement1 and 2, for use later - ELink has to match the preceding XLink, so the only
13684  2 possible PrefDirs are for a leading point & its two trailing PrefDirs.
13685 
13686  Enter loop - note that PrefDirElement changes each time round the loop - check if PrefDirElement XLinkPos faces buffers
13687  or a continuation, and fail if so. Check if reached a valid signal in ConsecSignalsRoute on any but firstpass
13688  (nonrecursive firstpass starts at a valid signal, and recursive firstpass always starts at points so doesn't matter
13689  for recursive calls), and fail if so as user should always select the next signal in a route.
13690  Create a new TPrefDirElement - SearchElement, from PrefDirElement.Conn[XLinkPos], & set all FixedTrackPiece &
13691  TrackElement values, ELink & ELinkPos, and also XLink & XLinkPos unless element is a leading point.
13692  Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
13693  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route),
13694  or if train on element (unless a bridge & train on different track).
13695  Check & fail for a fouled diagonal (unless element is a leading point - these checked later).
13696  Check element in EveryPrefDir with same ELink value & set PrefDirElement1, & also 2 if element is
13697  a leading point where both trailing directions are in EveryPrefDir, if not fail.
13698  Check if found RequiredPosition & that it's a signal/buffer/continuation if ConsecSignalsRoute set. If OK save in SearchVector with
13699  AutoSignals member set if AutoSigsFlag set, then return true.
13700  Check & fail if a buffer or continuation (if element = RequiredPosition will have succeeded in the above check.
13701 
13702  Now check if a leading point and if so set XLinkPos to the 'set' exit & check if that XLink is in EveryPrefDir,
13703  by comparing with PrefDirElement1 or 2, fail if not. If valid check for a fouled diagonal and fail if so. If OK
13704  store element in SearchVector with AutoSignals member set if AutoSigsFlag set & do a recursive search using
13705  this element and XLinkPos, other parameters are passed in without change. If succeed return true, else erase the last element in
13706  SearchVector (i.e the earlier stored leading point element prior to doing the recursive search) & set XLinkPos to the 'unset' exit to
13707  check the other trailing direction. Then proceed in same way as above, i.e. fouled diagonal & recursive search etc. If
13708  fail on this XLinkPos then have tried & failed on both ways out from the leading point so erase the searchvector & return false.
13709 
13710  If not a leading point store the element (can only be PrefDirElement1 as not a leading point), then set
13711  up the next loop values of PrefDirElement & XLinkPos from SearchElement & NextXLinkPos and repeat the while loop.
13712 */
13713 
13714 {
13715  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPreferredRoute," + PrefDirElement.LogPrefDir() + "," +
13716  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString(EndPosition) + "," +
13717  AnsiString((short)AutoSigsFlag));
13718  int VectorCount = 0;
13719  TPrefDirElement PrefDirElement1, PrefDirElement2, BlankElement;
13720 
13721 // check for a fouled diagonal for first element. Added for v1.3.2
13722  if((PrefDirElement.XLink == 1) || (PrefDirElement.XLink == 3) || (PrefDirElement.XLink == 7) || (PrefDirElement.XLink == 9))
13723  {
13724  if(AllRoutes->DiagonalFouledByRouteOrTrain(0, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.XLink))
13725  {
13726  for(int x = 0; x < VectorCount; x++)
13727  SearchVector.erase(SearchVector.end() - 1);
13728  Utilities->CallLogPop(2043);
13729  return false;
13730  }
13731  }
13732 
13733  bool FirstPass = true;
13734 
13735  while(true)
13736  {
13737  if(AutoSigsFlag && Track->IsLCAtHV(24, PrefDirElement.HLoc, PrefDirElement.VLoc))
13738  {
13739  Track->LCFoundInAutoSigsRoute = true;
13740  }
13741  if(Track->IsLCBarrierFlashingAtHV(1, PrefDirElement.HLoc, PrefDirElement.VLoc)) // can't set a route through a flashing barrier
13742  {
13743  for(int x = 0; x < VectorCount; x++)
13744  SearchVector.erase(SearchVector.end() - 1);
13745  Utilities->CallLogPop(1926);
13746  return false;
13747  }
13748  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == End) // buffers or continuation
13749  {
13750  for(int x = 0; x < VectorCount; x++)
13751  SearchVector.erase(SearchVector.end() - 1);
13752  Utilities->CallLogPop(236);
13753  return false;
13754  }
13755  if(!FirstPass && (ConsecSignalsRoute) && (PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal))
13756  // reached a valid signal that isn't the required position, user should always select the next
13757  // signal in a route so have to fail
13758  // won't affect recurive searches as for them the first pass element is always a point
13759  {
13760  for(int x = 0; x < VectorCount; x++)
13761  SearchVector.erase(SearchVector.end() - 1);
13762  Utilities->CallLogPop(237);
13763  return false;
13764  }
13765  FirstPass = false;
13766  int NextPosition = PrefDirElement.Conn[XLinkPos];
13767  TTrackElement NextTrackElement = Track->TrackElementAt(88, NextPosition);
13768  TPrefDirElement SearchElement(NextTrackElement);
13769  SearchElement.TrackVectorPosition = NextPosition;
13770  int NextELinkPos = PrefDirElement.ConnLinkPos[XLinkPos];
13771  SearchElement.ELinkPos = NextELinkPos;
13772  SearchElement.ELink = SearchElement.Link[NextELinkPos]; // Note ELink isn't necessarily 10 - last XLink, as last element may have
13773  // been a gap. Now have all FixedTrackPiece & TrackElement values, + TrackVectorPosition, ELink & ELinkPos
13774  int NextXLinkPos;
13775  if(SearchElement.ELinkPos == 0)
13776  NextXLinkPos = 1;
13777  if(SearchElement.ELinkPos == 1)
13778  NextXLinkPos = 0;
13779  if(SearchElement.ELinkPos == 2)
13780  NextXLinkPos = 3;
13781  if(SearchElement.ELinkPos == 3)
13782  NextXLinkPos = 2;
13783  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
13784  {
13785  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
13786 // note that may be buffers, continuation or gap
13787  SearchElement.XLinkPos = NextXLinkPos;
13788  }
13789 // can't set XLink or XLinkPos yet if the element is a leading point.
13790 
13791 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
13792  for(unsigned int x = 0; x < SearchVector.size(); x++)
13793  {
13794  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
13795  {
13796  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
13797  // OK if a bridge & routes on different tracks
13798  {
13799  for(int x = 0; x < VectorCount; x++)
13800  SearchVector.erase(SearchVector.end() - 1);
13801  Utilities->CallLogPop(238);
13802  return false;
13803  }
13804  }
13805  }
13806 
13807 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
13808  TAllRoutes::TRouteElementPair SecondPair;
13810  Track->TrackElementAt(89, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(90, SearchElement.TrackVectorPosition).VLoc, SecondPair);
13811  if(RoutePair.first > -1)
13812  {
13813  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
13814  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(12, RoutePair.first).GetFixedPrefDirElementAt(38,
13815  RoutePair.second).ELinkPos)))
13816  {
13817  // still OK if start of an expected route
13818  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(2, ReqPosRouteID)) || (RoutePair.second != 0))
13819  {
13820  for(int x = 0; x < VectorCount; x++)
13821  SearchVector.erase(SearchVector.end() - 1);
13822  Utilities->CallLogPop(239);
13823  return false; // only allow for start of an expected route
13824  }
13825  }
13826  }
13827  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
13828  {
13829  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
13830  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(13, SecondPair.first).GetFixedPrefDirElementAt(39,
13831  SecondPair.second).ELinkPos)))
13832  {
13833  // still OK if start of an expected route
13834  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(3, ReqPosRouteID)) || (SecondPair.second != 0))
13835  {
13836  for(int x = 0; x < VectorCount; x++)
13837  SearchVector.erase(SearchVector.end() - 1);
13838  Utilities->CallLogPop(240);
13839  return false; // only allow for start of an expected route
13840  }
13841  }
13842  }
13843 
13844 // check if a train on element, unless a bridge & train on different track
13845 // OK of same train as start element - no drop this
13846 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
13847  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
13848  {
13849  for(int x = 0; x < VectorCount; x++)
13850  SearchVector.erase(SearchVector.end() - 1);
13851  Utilities->CallLogPop(241);
13852  return false;
13853  }
13854  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
13855  {
13856  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeTrackPos01 > -1))
13857  {
13858  for(int x = 0; x < VectorCount; x++)
13859  SearchVector.erase(SearchVector.end() - 1);
13860  Utilities->CallLogPop(242);
13861  return false;
13862  }
13863  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeTrackPos23 > -1))
13864  {
13865  for(int x = 0; x < VectorCount; x++)
13866  SearchVector.erase(SearchVector.end() - 1);
13867  Utilities->CallLogPop(243);
13868  return false;
13869  }
13870  }
13871 
13872 // check for a fouled diagonal (if not leading point - these checked later - leading point XLink == -1)
13873  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
13874  {
13875  if(AllRoutes->DiagonalFouledByRouteOrTrain(7, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
13876  {
13877  for(int x = 0; x < VectorCount; x++)
13878  SearchVector.erase(SearchVector.end() - 1);
13879  Utilities->CallLogPop(244);
13880  return false;
13881  }
13882  }
13883 // check element in EveryPrefDir with same ELink (XLink may not be set) & save up to 2 elements (for leading point & 2 trailing PrefDirs)
13884 // note that point XLinks checked later, otherwise XLink fully defined by ELink so only need to check ELink
13885  bool InPrefDirFlag = false;
13886  PrefDirElement1 = BlankElement;
13887  PrefDirElement2 = BlankElement;
13888 
13889  bool FoundFlag;
13890  int PrefDirPos0 = -1;
13891  int PrefDirPos1 = -1;
13892  int PrefDirPos2 = -1;
13893  int PrefDirPos3 = -1;
13895  Track->TrackElementAt(92, SearchElement.TrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13896  int PrefDirVecPos[4] =
13897  {PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3};
13898  for(int x = 0; x < 4; x++)
13899  {
13900  int b = PrefDirVecPos[x];
13901  if((b > -1) && (EveryPrefDir->GetFixedPrefDirElementAt(40, b).ELink == SearchElement.ELink))
13902  {
13903  InPrefDirFlag = true;
13904  if(PrefDirElement1.TrackVectorPosition == -1)
13905  PrefDirElement1 = EveryPrefDir->GetFixedPrefDirElementAt(41, b);
13906  else
13907  PrefDirElement2 = EveryPrefDir->GetFixedPrefDirElementAt(42, b);
13908  }
13909  }
13910  if(!InPrefDirFlag)
13911  {
13912  for(int x = 0; x < VectorCount; x++)
13913  SearchVector.erase(SearchVector.end() - 1);
13914  Utilities->CallLogPop(245);
13915  return false;
13916  }
13917 
13918 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
13919 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
13920 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
13922  {
13923  for(int x = 0; x < VectorCount; x++)
13924  SearchVector.erase(SearchVector.end() - 1);
13925  Utilities->CallLogPop(1690);
13926  return false;
13927  }
13928 
13929 // check if found it
13930  if(SearchElement.TrackVectorPosition == RequiredPosition)
13931  {
13932 // need to ensure a signal/buffer/continuation if ConsecSignalsRoute set,
13933  if(ConsecSignalsRoute && (SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End) &&
13934  (SearchElement.Config[SearchElement.XLinkPos] != Continuation))
13935  {
13936  for(int x = 0; x < VectorCount; x++)
13937  SearchVector.erase(SearchVector.end() - 1);
13938  Utilities->CallLogPop(246);
13939  return false;
13940  } // if(ConsecSignalsRoute && (SearchElement.Config[SearchElement.XLinkPos] != Signal).......
13941  if(AutoSigsFlag)
13942  {
13943  PrefDirElement1.AutoSignals = true;
13944  }
13945  if(ConsecSignalsRoute)
13946  {
13947  PrefDirElement1.ConsecSignals = true;
13948  }
13950  {
13952  {
13953  TrainController->StopTTClockMessage(76, "Can't create an automatic signal route through a level crossing");
13955  }
13956  for(int x = 0; x < VectorCount; x++)
13957  SearchVector.erase(SearchVector.end() - 1);
13958  Utilities->CallLogPop(1928);
13959  return false;
13960  }
13961  SearchVector.push_back(PrefDirElement1); // must be 1 as it's a simple element
13962  VectorCount++; // not really needed but include for tidyness
13963  TotalSearchCount++;
13964  Utilities->CallLogPop(247);
13965  return true;
13966  } // if(SearchElement.TrackVectorPosition == RequiredPosition)
13967 // check if a buffer or continuation (end of search on this leg if not found by now)
13968  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
13969  {
13970  for(int x = 0; x < VectorCount; x++)
13971  SearchVector.erase(SearchVector.end() - 1);
13972  Utilities->CallLogPop(248);
13973  return false;
13974  }
13975 // check if SearchVector exceeds a size of 150
13976  if(SearchVector.size() > 150)
13977  {
13978  for(int x = 0; x < VectorCount; x++)
13979  SearchVector.erase(SearchVector.end() - 1);
13980  Utilities->CallLogPop(1420);
13981  return false;
13982  }
13983 // check if reached a leading point
13984  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
13985  {
13986 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
13987  int SearchPos1 = SearchElement.Attribute + 1;
13988  int SearchPos2;
13989  if(SearchPos1 == 2)
13990  SearchPos1++;
13991  if(SearchPos1 == 1)
13992  SearchPos2 = 3;
13993  else
13994  SearchPos2 = 1;
13995  SearchElement.XLink = SearchElement.Link[SearchPos1];
13996  SearchElement.XLinkPos = SearchPos1;
13997  InPrefDirFlag = false;
13998  if(SearchElement.XLink == PrefDirElement1.XLink)
13999  {
14000  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
14001  InPrefDirFlag = true;
14002  }
14003  else if(SearchElement.XLink == PrefDirElement2.XLink)
14004  {
14005  SearchElement = PrefDirElement2;
14006  InPrefDirFlag = true;
14007  }
14008 // push element with XLink set to position [SearchPos1] if on a PrefDir
14009  if(InPrefDirFlag)
14010  {
14011 // check for a fouled diagonal for leading point for XLinkPos == 1)
14012  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
14013  {
14014  if(AllRoutes->DiagonalFouledByRouteOrTrain(1, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
14015  {
14016  for(int x = 0; x < VectorCount; x++)
14017  SearchVector.erase(SearchVector.end() - 1);
14018  Utilities->CallLogPop(249);
14019  return false;
14020  }
14021  }
14022  if(AutoSigsFlag)
14023  {
14024  SearchElement.AutoSignals = true;
14025  }
14026  if(ConsecSignalsRoute)
14027  {
14028  SearchElement.ConsecSignals = true;
14029  }
14030  SearchVector.push_back(SearchElement);
14031  VectorCount++;
14032  TotalSearchCount++;
14033 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
14034  if(SearchForPreferredRoute(6, SearchElement, SearchPos1, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
14035  AutoSigsFlag))
14036  {
14038  {
14040  {
14041  TrainController->StopTTClockMessage(77, "Can't create an automatic signal route through a level crossing");
14043  }
14044  for(int x = 0; x < VectorCount; x++)
14045  SearchVector.erase(SearchVector.end() - 1);
14046  Utilities->CallLogPop(1929);
14047  return false;
14048  }
14049  Utilities->CallLogPop(250);
14050  return true;
14051  }
14052  else
14053  {
14054 // remove leading point with XLinkPos [1]
14055  SearchVector.erase(SearchVector.end() - 1);
14056  VectorCount--;
14057  }
14058  }
14059 // XLink set to position [SearchPos2]
14060  SearchElement.XLink = SearchElement.Link[SearchPos2];
14061  SearchElement.XLinkPos = SearchPos2;
14062  if(SearchElement.XLink == PrefDirElement1.XLink)
14063  {
14064  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
14065  }
14066  else if(SearchElement.XLink == PrefDirElement2.XLink)
14067  {
14068  SearchElement = PrefDirElement2;
14069  }
14070  else // failed to find a valid exit from the point
14071  {
14072  for(int x = 0; x < VectorCount; x++)
14073  SearchVector.erase(SearchVector.end() - 1);
14074  Utilities->CallLogPop(251);
14075  return false;
14076  }
14077 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
14078  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
14079  {
14080  if(AllRoutes->DiagonalFouledByRouteOrTrain(2, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
14081  {
14082  for(int x = 0; x < VectorCount; x++)
14083  SearchVector.erase(SearchVector.end() - 1);
14084  Utilities->CallLogPop(252);
14085  return false;
14086  }
14087  }
14088 // push element with XLink set to position [SearchPos2]
14089  if(AutoSigsFlag)
14090  {
14091  SearchElement.AutoSignals = true;
14092  }
14093  if(ConsecSignalsRoute)
14094  {
14095  SearchElement.ConsecSignals = true;
14096  }
14097  SearchVector.push_back(SearchElement);
14098  VectorCount++;
14099  TotalSearchCount++;
14100 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
14101  if(SearchForPreferredRoute(7, SearchElement, SearchPos2, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
14102  AutoSigsFlag))
14103  {
14105  {
14107  {
14108  TrainController->StopTTClockMessage(78, "Can't create an automatic signal route through a level crossing");
14110  }
14111  for(int x = 0; x < VectorCount; x++)
14112  SearchVector.erase(SearchVector.end() - 1);
14113  Utilities->CallLogPop(1930);
14114  return false;
14115  }
14116  Utilities->CallLogPop(1592);
14117  return true;
14118  }
14119  else
14120  {
14121  for(int x = 0; x < VectorCount; x++)
14122  SearchVector.erase(SearchVector.end() - 1);
14123  Utilities->CallLogPop(253);
14124  return false;
14125  }
14126  } // if leading point
14127 // here if ordinary element, push it, inc vector & update PrefDirElement ready for next element on PrefDir
14128  SearchElement = PrefDirElement1;
14129  if(AutoSigsFlag)
14130  {
14131  SearchElement.AutoSignals = true;
14132  }
14133  if(ConsecSignalsRoute)
14134  {
14135  SearchElement.ConsecSignals = true;
14136  }
14137  SearchVector.push_back(SearchElement);
14138  VectorCount++;
14139  TotalSearchCount++;
14140  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
14141  PrefDirElement = SearchElement;
14142  } // while(true)
14143 }
14144 
14145 // ---------------------------------------------------------------------------
14146 
14147 void TOneRoute::ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
14148 {
14149 /*
14150  For routes, as opposed to PrefDirs, the new route elements are first entered into SearchVector,
14151  and the new or extended route created from that. Hence action varies depending on whether
14152  it is a completely new route, or an extension of an existing route at the beginning or the end.
14153  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
14154  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
14155 
14156  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
14157  Check if route end selection is in an existing route (ReqPosRouteID > -1), and if so proceed as follows:-
14158  if both new and existing routes non-autosig, add the old route to the SearchVector then delete the old route;
14159  if both new and existing routes autosig, add the old route to the SearchVector then delete the old route;
14160  in both the above cases if RequPosRouteNumber is less than StartSelectionRouteNumber then StartSelectionRouteNumber
14161  is decremented;
14162  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element)
14163  from the existing route, then enter the new route into the AllRoutesVector;
14164  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
14165  then enter the new route into the AllRoutesVector.
14166 
14167  Check if StartSelectionRouteID set (extending an existing route) and if so proceed as follows:-
14168  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector);
14169  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector);
14170  in both the above cases validate the extended route, then call SetRoutePoints & SetRouteSignals for the extended route and return.
14171  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
14172  then add it to the start of the new route, then check its validity, enter it into the AllRoutesVector, call SetRoutePoints & SetRouteSignals
14173  for the new route and return;
14174  if new route non-autosig and existing route autosig, leave the existing route as it is, check its validity, then just enter the new
14175  route into the AllRoutesVector, finally call SetRoutePoints & SetRouteSignals for the new route and return.
14176 
14177  If not returned by now the route in SearchVector is to be added as a new route, so check its validity, create a new route using
14178  StoreOneRoute, call SetRoutePoints & SetRouteSignals and return. In practice the validity check, storage into AllRoutesVector and
14179  SetRoutePoints & SetRouteSignals call are combined for the above three cases.
14180 */
14181  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddPreferredRouteSearchVector," +
14182  AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString((short)AutoSigsFlag));
14183  if(SearchVector.size() < 1)
14184  {
14185  Utilities->CallLogPop(254);
14186  return;
14187  }
14189  if(!ValidatePrefDir(3)) // check the new route elements in SearchVector
14190  {
14191  Utilities->CallLogPop(255);
14192  return;
14193  }
14194 
14195  TAllRoutes::TLockedRouteClass LockedRouteObject;
14196 
14198  unsigned int TruncatePrefDirPosition = 0;
14199 
14200  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartRouteNumber as would have failed in GetNextRouteElement
14201 /* if have ReqPosRouteID:
14202  if both new and existing routes non-autosig, then add the old route to the SearchVector then delete the old route
14203  if both new and existing routes autosig, then add the old route to the SearchVector then delete the old route
14204  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element) from
14205  the existing route, then enter the new route into the AllRoutesVector
14206  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
14207  then enter the new route into the AllRoutesVector
14208 */
14209  {
14212  {
14213  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(21, ReqPosRouteID).PrefDirSize();
14214  x++) // start at 1 as first element already in SearchVector
14215  {
14217  }
14218  // note that route numbers in map adjusted when ReqPos route cleared
14220  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
14221  // set during ClearRouteDuringRouteBuildingAt
14223  {
14226  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
14227  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
14228  }
14229  }
14231  {
14233  AllRoutes->RemoveRouteElement(3, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
14234  }
14236  {
14237  SearchVector.pop_back();
14238  }
14239  }
14240 
14241  if(StartSelectionRouteID > -1)
14242 /* if have StartSelectionRouteID:
14243  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector)
14244  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector)
14245  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
14246  then add it to the start of the new route, then enter the new route into the AllRoutesVector
14247  if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
14248 */
14249  {
14251  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
14252  {
14255  {
14256  int RouteNumber = AllRoutes->GetRouteVectorNumber(0, StartSelectionRouteID);
14257  for(unsigned int x = 0; x < SearchVector.size(); x++)
14258  {
14260  RouteNumber, GetFixedSearchElementAt(3, x));
14261  // find & store locked route truncate position in PrefDirVector for later use
14263  {
14264  if(GetFixedSearchElementAt(15, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
14265  {
14266  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(172, RouteNumber).PrefDirSize() - 1;
14267  }
14268  }
14269  }
14271  {
14272  throw Exception("Error - failed to validate extended route for preferred route");
14273  }
14276  if(!AutoSigsFlag)
14277  {
14278  AllRoutes->GetModifiableRouteAtIDNumber(7, StartSelectionRouteID).SetLCChangeValues(0, true); // ConsecSignalsRoute is true
14279  }
14280  // now add the reinstated locked route if required and set signals accordingly
14282  {
14283  LockedRouteObject.RouteNumber = RouteNumber;
14284  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
14285  // now reset the signals for the locked route
14286  AllRoutes->SetAllRearwardsSignals(9, 0, RouteNumber, TruncatePrefDirPosition);
14287  for(int c = AllRoutes->GetFixedRouteAt(173, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
14288  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
14289  // return all signals to red in route section to be truncated
14290  {
14291  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(174, RouteNumber).PrefDirVector.at(c);
14292  TTrackElement & TrackElement = Track->TrackElementAt(812, PrefDirElement.TrackVectorPosition);
14293  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
14294  {
14295  TrackElement.Attribute = 0;
14296  Track->PlotSignal(10, TrackElement, Display);
14297  Display->PlotOutput(113, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
14298  Display->PlotOutput(114, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
14299  }
14300  }
14301  }
14302  AllRoutes->CheckMapAndRoutes(1); // test
14303  Utilities->CallLogPop(256);
14304  return;
14305  }
14307  {
14310  RouteElement.AutoSignals = true;
14311  RouteElement.EXGraphicPtr = RouteElement.GetRouteGraphicPtr(AutoSigsFlag, true); // true for ConsecSignalsRoute
14312  RouteElement.EntryDirectionGraphicPtr = RouteElement.GetDirectionRouteGraphicPtr(AutoSigsFlag, true); // true for ConsecSignalsRoute
14313  AllRoutes->RemoveRouteElement(4, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
14314  SearchVector.insert(SearchVector.begin(), 1, RouteElement);
14315  }
14316  }
14317  else
14318  {
14320  }
14321 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the
14322 // AllRoutesVector hence nothing to do here
14323  }
14324 
14325  PrefDirVector = SearchVector; // need to copy again since SearchVector may have been extended
14326  if(!ValidatePrefDir(5)) // validate PrefDir for all new route elements
14327  {
14328  throw Exception("Error - failed to validate single route for preferred route");
14329  }
14330  AllRoutes->StoreOneRoute(1, this);
14331  AllRoutes->GetModifiableRouteAt(3, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(1); // new addition
14332  AllRoutes->GetModifiableRouteAt(16, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(5); // new addition
14333  if(!AutoSigsFlag)
14334  {
14335  AllRoutes->GetModifiableRouteAt(18, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(1, true); // ConsecSignalsRoute is true
14336  }
14337  AllRoutes->CheckMapAndRoutes(2); // test
14338  Utilities->CallLogPop(257);
14339 }
14340 
14341 // ---------------------------------------------------------------------------
14342 
14343 bool TOneRoute::GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, bool Callon) // Return true if OK.
14344 {
14345 /*
14346  [Note: original intention was to allow both consecutive signals and non-consecutive signals for routes
14347  on track with or without pref dirs set, hence the bool ConsecSignalsRoute, subsequently decided to
14348  make all unrestricted routes nonconsecutive signals, so that parameter will always be false. leave
14349  as is in case wish to change at a later time]
14350 
14351  If Callon true then called to set an unrestricted call-on route - suppress messages
14352  Clear the PrefDir and search vectors using ClearRoute(). Check selection matches a TrackElement
14353  & ensure signal/buffers/continuation.
14354  Note that can't select ConsecSignalsRoute for non-preferred routes.
14355  Check if train on element & disallow.
14356  Set default values for retained parameters:-
14357  StartRoutePosition = TrackVectorPosition of the element to be used as the start of the route;
14358  StartSelectionRouteID = route that selection starts in if there is one;
14359 
14360  Create 2 PrefDirElements from the TrackElement, setting all values corresponding to the 2 possible PrefDirs
14361  through the element (can only be 2 as 3 & 4 ended elements aren't allowed) & make an EXNumber check for
14362  validity. This is just for safety reasons, the PrefDir values aren't used.
14363  StartElement1 & 2 are set to these PrefDirelements.
14364 
14365  There is no need to check that the element lies in a PrefDir for nonpreferred selections.
14366 
14367  Check if in an existing route & if so only allow last element to be selected - ensure it has somewhere to go!
14368  Set StartElement1, StartSelectionRouteID and StartRoutePosition to correspond to the route end element and
14369  blank StartElement2 (only want to use the route element), then return true.
14370  Check if adjacent to start or end of an existing route & disallow if so.
14371  If not in a route and not failed so far then reset all Link, all LinkPos, & EXNumber values to -1, and CheckCount
14372  to 4 for StartElement1, & blank StartElement2. The remaining data members will be set later in
14373  SetRemainingSearchVectorValues().
14374  Finally add the required element to the SearchVector & return true.
14375 */
14376  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNonPreferredRouteStartElement," + AnsiString(HLoc) + "," +
14377  AnsiString(VLoc) + "," + AnsiString((short)Callon));
14378  ClearRoute();
14379  int TrackVectorPosition;
14380  TTrackElement TrackElement;
14381  TPrefDirElement FirstElement, LastElement;
14382 
14383  if(!(Track->FindNonPlatformMatch(9, HLoc, VLoc, TrackVectorPosition, TrackElement)))
14384  {
14385  Utilities->CallLogPop(258);
14386  return false;
14387  }
14388  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
14389  {
14390  if(!Callon)
14391  TrainController->StopTTClockMessage(34, "Can't select points, bridge or crossover when route building");
14392 // makes later adjacent route checks too complicated
14393  Utilities->CallLogPop(259);
14394  return false;
14395  }
14396 
14397  if(Track->IsLCAtHV(21, HLoc, VLoc))
14398  {
14399  TrainController->StopTTClockMessage(74, "Can't start a route on a level crossing");
14400  Utilities->CallLogPop(1910);
14401  return false;
14402  }
14403 
14404 // check if selected a train & disallow if so
14405  if(TrackElement.TrainIDOnElement > -1)
14406  {
14407  if(!Callon)
14408  TrainController->StopTTClockMessage(35, "Can't start a route on a train");
14409  Utilities->CallLogPop(260);
14410  return false;
14411  }
14412 
14413 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
14414  TPrefDirElement PrefDirElement;
14415  int LockedVectorNumber;
14416 
14417  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(3, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
14418  {
14419  if(!Callon)
14420  TrainController->StopTTClockMessage(36, "Can't start a route on a locked route");
14421  Utilities->CallLogPop(261);
14422  return false;
14423  }
14424  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(4, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
14425  {
14426  if(!Callon)
14427  TrainController->StopTTClockMessage(37, "Can't start a route on a locked route");
14428  Utilities->CallLogPop(262);
14429  return false;
14430  }
14431 
14433 // AdjacentStartRouteNumber = -1;
14434  StartRoutePosition = TrackVectorPosition;
14435 // StartRouteSelectPosition = TrackVectorPosition;
14436 
14437  TPrefDirElement PrefDirElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
14438  TPrefDirElement PrefDirElement2(TrackElement);
14439 
14440  PrefDirElement1.TrackVectorPosition = TrackVectorPosition;
14441  PrefDirElement2.TrackVectorPosition = TrackVectorPosition;
14442  TPrefDirElement BlankElement;
14443 
14444  PrefDirElement1.ELinkPos = 0;
14445  PrefDirElement1.XLinkPos = 1;
14446  PrefDirElement1.ELink = PrefDirElement1.Link[0];
14447  PrefDirElement1.XLink = PrefDirElement1.Link[1];
14448  if(!(PrefDirElement1.EntryExitNumber()))
14449  {
14450  throw Exception("Error, No EXNumber for PrefDirElement1 in GetNonPreferredRouteStartElement");
14451  // no need for bridge check as bridge selections not allowed
14452  }
14453  PrefDirElement1.CheckCount = 9;
14454  PrefDirElement2.ELinkPos = 1;
14455  PrefDirElement2.XLinkPos = 0;
14456  PrefDirElement2.ELink = PrefDirElement2.Link[1];
14457  PrefDirElement2.XLink = PrefDirElement2.Link[0];
14458  if(!(PrefDirElement2.EntryExitNumber()))
14459  {
14460  throw Exception("Error, No EXNumber for PrefDirElement2 in GetNonPreferredRouteStartElement");
14461  }
14462  PrefDirElement2.CheckCount = 9; // both now set
14463 
14464 // set StartElements to the above PrefDirElements
14465  StartElement1 = PrefDirElement1;
14466  StartElement2 = PrefDirElement2;
14467 
14468 // no PrefDir check needed as doesn't need to be in a PrefDir
14469 
14470 // look for exact match in a route first - can't be a 3 or 4 track element so only need to look for one TRouteElementPair
14472  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(1, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14473 
14474  if(RoutePair.first > -1)
14475  {
14476  if(RoutePair.second != AllRoutes->GetFixedRouteAt(31, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
14477  {
14478  if(!Callon)
14479  TrainController->StopTTClockMessage(38, "Can't start a route within or at the start of an existing route");
14480  Utilities->CallLogPop(263);
14481  return false;
14482  }
14483  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(32, RoutePair.first).GetFixedPrefDirElementAt(56, RoutePair.second);
14484  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
14485  {
14486  if(!Callon)
14487  TrainController->StopTTClockMessage(39, "No forward connection from this position");
14488  Utilities->CallLogPop(264);
14489  return false;
14490  }
14491  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(11, RouteElement.Conn[RouteElement.XLinkPos],
14492  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
14493  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14494  {
14495  if(!Callon)
14496  TrainController->StopTTClockMessage(40, "Can't start a route at an element that links forward into an existing route");
14497  Utilities->CallLogPop(265);
14498  return false;
14499  }
14500  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(162, RoutePair.first).RouteID);
14502  AllRoutes->GetFixedRouteAt(34, RoutePair.first).PrefDirSize() - 1); // last element
14503  StartElement2 = BlankElement; // only use the route element
14505  Utilities->CallLogPop(266);
14506  return true; // all retained values set
14507  }
14508 
14509  else // selection not in an existing route
14510  {
14511 // check if it's adjacent to start of an an existing route,
14512  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14513  {
14514  FirstElement = AllRoutes->GetFixedRouteAt(35, a).GetFixedPrefDirElementAt(58, 0);
14515  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
14516  {
14517  if(!Callon)
14518  TrainController->StopTTClockMessage(41, "Can't make selection adjacent to start of another route");
14519  Utilities->CallLogPop(267);
14520  return false;
14521  }
14522  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
14523  {
14524  if(!Callon)
14525  TrainController->StopTTClockMessage(42, "Can't make selection adjacent to start of another route");
14526  Utilities->CallLogPop(268);
14527  return false;
14528  }
14529  }
14530 // check if it's adjacent to end of an an existing route,
14531  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14532  {
14534  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
14535  {
14536  if(!Callon)
14537  TrainController->StopTTClockMessage(43, "Can't start a route adjacent to the end of an existing route");
14538  Utilities->CallLogPop(269);
14539  return false;
14540  }
14541  }
14542  // not in a route or adjacent to start or end of a route
14543  // in this case reset all variable values to -1 & CheckCount to 4
14544  StartElement1.ELink = -1;
14545  StartElement1.ELinkPos = -1;
14546  StartElement1.XLink = -1;
14547  StartElement1.XLinkPos = -1;
14548  StartElement1.EXNumber = -1;
14550  StartElement2 = BlankElement;
14551  SearchVector.push_back(StartElement1);
14552  Utilities->CallLogPop(270);
14553  return true;
14554  }
14555 }
14556 
14557 // ---------------------------------------------------------------------------
14558 bool TOneRoute::GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
14559 
14560 /*
14561  If Callon true then called to set an unrestricted call-on route - suppress messages & allow points to be selected
14562 
14563  Declare the following integers:-
14564  EndPosition - TrackVectorPosition for the selection;
14565  ReqPosRouteID - for the existing route selected, set to -1 if not used and initially;
14566  Check if selection is a valid track element and set EndPosition.
14567  Cancel if select original start element, then check that not points, bridge or crossover.
14568  Check & fail if a train is present at the selection.
14569  Create & set 2 PrefDirElements EndElement1 & 2 corresponding to the 2 possible PrefDir elements (similar to StartElement1 & 2
14570  in GetNonPreferredRouteStartElement) & make an EXNumber validity check just for safety reasons - the PrefDir values are not used.
14571  No check needed for selection in EveryPrefDir.
14572  Check if selection in an existing route & if so ensure it's the start element and that it doesn't have an 'End' facing the start.
14573  If it is the start of a route set ReqPosRouteID, EndPosition & EndElement1 to the start of route values and blank EndElement2
14574  as don't need it if in a route.
14575  Check if selection adj to start or end of a route and disallow.
14576  Fail if select same route as starting route, though should already have failed earlier if this is so.
14577 
14578  If there's a StartSelectionRouteID then StartElement1 will be set to
14579  the last entry in the selected route so use SearchForNonPreferredRoute to search for the selected end element from this
14580  start element. If succeed then complete the search vector values (since not on a PrefDir) & return true, for Interface
14581  to handle the flashing & time delay. After the delay completes the Interface flasher calls ConvertAndAddNonPreferredRouteSearchVector
14582  to add the new route to the AllRoutesVectorPtr.
14583  If no starting route then StartElement1 only has basic values set & is in the SearchVector, and StartElement2 is blank.
14584  Check if the selected element is adjacent to the starting position and if so set the route to go directly to it (as opposed to
14585  going round a long loop to get to it just because that XLinkPos happens to be chosen first).
14586  If not adjacent then search on the two possible ways out of StartElement1 providing it isn't facing an 'End'. If succeed complete
14587  the search vector values and return.
14588  If not returned yet then have failed to find the required element so return false with no message.
14589 */
14590 
14591 {
14592 // get EndPosition
14593  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextNonPreferredRouteElement," + AnsiString(HLoc) + "," +
14594  AnsiString(VLoc));
14595  int EndPosition;
14596 
14597  TotalSearchCount = 0;
14598  ReqPosRouteID = IDInt(-1); // for not used
14599  TTrackElement TrackElement;
14600  TPrefDirElement BlankElement;
14601 
14602  if(!(Track->FindNonPlatformMatch(10, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
14603  {
14604  Utilities->CallLogPop(271);
14605  return false;
14606  }
14607 // EndPosition = EndSelectPosition;
14608 // cancel selection if on original start element
14609  if(EndPosition == StartRoutePosition)
14610  {
14611  Utilities->CallLogPop(272);
14612  return false;
14613  }
14614 
14615  if(Track->IsLCAtHV(22, HLoc, VLoc))
14616  {
14617  TrainController->StopTTClockMessage(75, "Can't end a route on a level crossing");
14618  Utilities->CallLogPop(1911);
14619  return false;
14620  }
14621 
14622  if((TrackElement.TrackType == Points) && !Callon)
14623  {
14624  if(!Callon)
14625  TrainController->StopTTClockMessage(44, "Can't select points, bridge or crossover when route building");
14626 // makes later adjacent route checks too complicated
14627  Utilities->CallLogPop(273);
14628  return false;
14629  }
14630 
14631  if((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
14632  {
14633  if(!Callon)
14634  TrainController->StopTTClockMessage(71, "Can't select points, bridge or crossover when route building");
14635 // makes later adjacent route checks too complicated
14636  Utilities->CallLogPop(1861);
14637  return false;
14638  }
14639 
14640 // check if train on element
14641  if(TrackElement.TrainIDOnElement > -1)
14642  {
14643  if(!Callon)
14644  TrainController->StopTTClockMessage(45, "Can't end a route on a train");
14645  Utilities->CallLogPop(274);
14646  return false;
14647  }
14648 
14649 // set the 2 EndElements corresponding to the 2 possible PrefDirs for the selected element (for safety reasons - to ensure EXNumber validity
14650 // check passed)
14651  TPrefDirElement EndElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
14652  TPrefDirElement EndElement2(TrackElement);
14653 
14654  EndElement1.TrackVectorPosition = EndPosition;
14655  EndElement2.TrackVectorPosition = EndPosition;
14656  EndElement1.ELinkPos = 0;
14657  EndElement1.XLinkPos = 1;
14658  EndElement1.ELink = EndElement1.Link[0];
14659  EndElement1.XLink = EndElement1.Link[1];
14660  if(!(EndElement1.EntryExitNumber()))
14661  {
14662  throw Exception("Error, No EXNumber for EndElement1 in GetNonPreferredRouteStartElement");
14663  }
14664  EndElement1.CheckCount = 9;
14665  EndElement2.ELinkPos = 1;
14666  EndElement2.XLinkPos = 0;
14667  EndElement2.ELink = EndElement2.Link[1];
14668  EndElement2.XLink = EndElement2.Link[0];
14669  if(!(EndElement2.EntryExitNumber()))
14670  {
14671  throw Exception("Error, No EXNumber for EndElement2 in GetNonPreferredRouteStartElement");
14672  }
14673  EndElement2.CheckCount = 9; // both now set
14674 
14675 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
14676 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
14677 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
14678 
14679  if(EndElement1.HLoc >= StartElement1.HLoc)
14680  {
14682  SearchLimitHighH = EndElement1.HLoc + 15;
14683  }
14684  else
14685  {
14686  SearchLimitLowH = EndElement1.HLoc - 15;
14688  }
14689 
14690  if(EndElement1.VLoc >= StartElement1.VLoc)
14691  {
14693  SearchLimitHighV = EndElement1.VLoc + 15;
14694  }
14695  else
14696  {
14697  SearchLimitLowV = EndElement1.VLoc - 15;
14699  }
14700 
14701 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
14702  check & TotalSearchCounts check
14703  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
14704  {
14705  if(!Callon) TrainController->StopTTClockMessage(66, "Unable to reach the selected element - too far ahead");
14706  Utilities->CallLogPop(1694);
14707  return false;
14708  }
14709 */
14710 // don't need EveryPrefDir check for NonPreferredRoute
14711 
14712 // check if in an existing route - can't be a 3 or 4 track element so only one TRouteElementPair to be set
14713 // bool InRoute = false;
14715  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(2, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14716 
14717  if(RoutePair.first > -1)
14718  {
14719  if(RoutePair.second != 0) // not first element in existing route so no good
14720  {
14721  if(!Callon)
14722  TrainController->StopTTClockMessage(46, "Can't end a route within or at the end of an existing route");
14723  Utilities->CallLogPop(275);
14724  return false;
14725  }
14726  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(38, RoutePair.first).GetFixedPrefDirElementAt(60, RoutePair.second);
14727 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
14728  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(12, RouteElement.Conn[RouteElement.ELinkPos],
14729  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
14730  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14731  {
14732  if(!Callon)
14733  TrainController->StopTTClockMessage(47, "Can't start a route within or at the end of an existing route");
14734  Utilities->CallLogPop(276);
14735  return false;
14736  }
14737  EndElement1 = AllRoutes->GetFixedRouteAt(39, RoutePair.first).GetFixedPrefDirElementAt(61, 0);
14738  EndElement2 = BlankElement; // only need the route element
14739  EndPosition = EndElement1.TrackVectorPosition;
14740  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(161, RoutePair.first).RouteID);
14741  }
14742 
14743 // check if adjacent to start of an existing route and disallow (unless start of existing route is also the start of this route)
14744  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14745  {
14746  int AdjPosition = AllRoutes->GetFixedRouteAt(40, a).GetFixedPrefDirElementAt(62, 0).TrackVectorPosition;
14747  int AdjLinkPos = AllRoutes->GetFixedRouteAt(219, a).GetFixedPrefDirElementAt(245, 0).ELinkPos; // added at v1.3.1
14748 // if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
14749 // && (AdjPosition != StartRoutePosition))
14750  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
14751  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14752  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos) && (AdjPosition != StartRoutePosition))
14753  {
14754  if(!Callon)
14755  TrainController->StopTTClockMessage(48, "Can't end a route adjacent to the start of an existing route");
14756  Utilities->CallLogPop(277);
14757  return false;
14758  }
14759 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
14760 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (AdjPosition != StartRoutePosition))
14761  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
14762  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14763  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos) &&
14764  (AdjPosition != StartRoutePosition))
14765  {
14766  if(!Callon)
14767  TrainController->StopTTClockMessage(49, "Can't end a route adjacent to the start of an existing route");
14768  Utilities->CallLogPop(278);
14769  return false;
14770  }
14771 
14772 // check if adjacent to end of a route & disallow (unless end of existing route is the start of this route - i.e. extending route by 1 element)
14774  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition) &&
14775  (EndOfRouteElement.TrackVectorPosition != StartRoutePosition))
14776  {
14777  if(!Callon)
14778  TrainController->StopTTClockMessage(50, "Can't end a route adjacent to the end of an existing route");
14779  Utilities->CallLogPop(279);
14780  return false;
14781  }
14782  }
14783 
14784 // check for same route as start element
14786  {
14787  if(!Callon)
14788  TrainController->StopTTClockMessage(51, "Can't select same route as started in");
14789  Utilities->CallLogPop(280);
14790  return false;
14791  }
14792 
14793 // check for a looping route
14794  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
14795  {
14797  {
14798  if(!Callon)
14799  TrainController->StopTTClockMessage(70, "Can't create a route that loops back on itself");
14800  Utilities->CallLogPop(1845);
14801  return false;
14802  }
14803  }
14804 
14805 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
14806 // so search from this element.
14807 
14808  TTrackElement &TempElement1 = StartElement1; // this needed to avoid a TTrackElement construction ambiguity in later search function
14809 
14810  if(StartSelectionRouteID > -1)
14811  {
14812  if(SearchForNonPreferredRoute(0, TempElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID))
14813  {
14815  if(PointsToBeChanged(0))
14816  {
14817  PointsChanged = true;
14818  }
14819  Utilities->CallLogPop(281);
14820  return true;
14821  }
14822  else
14823  {
14824  if(!Callon)
14826  Utilities->CallLogPop(282);
14827  return false;
14828  }
14829  }
14830  else // no starting route, so StartElement1 only has basic values set & is in SearchVector, StartElement2 is blank
14831  // search on the 2 ways out of the element, which has to be a 2-ended element
14832  {
14833 // check if selection adjacent to start element and if so use that
14834  if(SearchVector.at(0).Conn[0] == EndPosition)
14835  {
14836  if(SearchForNonPreferredRoute(1, TempElement1, 0, EndPosition, ReqPosRouteID))
14837  {
14839  if(PointsToBeChanged(1))
14840  {
14841  PointsChanged = true;
14842  }
14843  Utilities->CallLogPop(283);
14844  return true;
14845  }
14846  else
14847  {
14848  if(!Callon)
14850  Utilities->CallLogPop(284);
14851  return false;
14852  }
14853  }
14854  else if(SearchVector.at(0).Conn[1] == EndPosition)
14855  {
14856  if(SearchForNonPreferredRoute(2, TempElement1, 1, EndPosition, ReqPosRouteID))
14857  {
14859  if(PointsToBeChanged(2))
14860  {
14861  PointsChanged = true;
14862  }
14863  Utilities->CallLogPop(285);
14864  return true;
14865  }
14866  else
14867  {
14868  if(!Callon)
14870  Utilities->CallLogPop(286);
14871  return false;
14872  }
14873  }
14874  // now start off in the best direction
14875  int BestPos = Track->FindClosestLinkPosition(1, StartRoutePosition, EndPosition); // can only be 0 or 1
14876 
14877  if(SearchVector.at(0).Config[BestPos] != End)
14878  {
14879  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14880  if(SearchForNonPreferredRoute(3, TempElement1, BestPos, EndPosition, ReqPosRouteID))
14881  {
14883  if(PointsToBeChanged(3))
14884  {
14885  PointsChanged = true;
14886  }
14887  Utilities->CallLogPop(287);
14888  return true;
14889  }
14890  }
14891  if(SearchVector.at(0).Config[1 - BestPos] != End)
14892  {
14893  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14894  if(SearchForNonPreferredRoute(4, TempElement1, (1 - BestPos), EndPosition, ReqPosRouteID))
14895  {
14897  if(PointsToBeChanged(4))
14898  {
14899  PointsChanged = true;
14900  }
14901  Utilities->CallLogPop(288);
14902  return true;
14903  }
14904  }
14905  }
14906  if(!Callon)
14908  Utilities->CallLogPop(289);
14909  return false;
14910 }
14911 
14912 // ---------------------------------------------------------------------------
14913 
14914 bool TOneRoute::SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID)
14915 /*
14916  This is very similar to the preferred route search, but without the need to ensure all elements are in EveryPrefDir.
14917  Returns true for successful search with SearchVector containing the new route elements. Enter with CurrentTrackElement
14918  stored in SearchVector unless it's in an existing route, & XLinkPos set to the link to search on.
14919  Keep a count of entries in SearchVector during the current function call, so that this number can be
14920  erased for an unproductive branch search.
14921  First check (within the loop) whether XLink leads to an End & return false if so.
14922  Create a NextTrackElement from Current & XLinkPos, and a PrefDirElement (SearchElement) from that, setting as many values as
14923  possible. Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
14924  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route), if
14925  train on element (unless a bridge & train on different track), or if element
14926  fouls an existing diagonal route (except if element is a leading point - these checked later).
14927  Then check if found required element. If so save it & return true.
14928  If not the required element check if buffer or continuation, & if so erase all searchvector
14929  & return false. If OK check if a leading point and if so do up to 2 recursive searches for the 2 exits (trying the 'set' exit first),
14930  checking in each case whether the element fouls an existing diagonal route. If fail on both exits erase searchvector & return false.
14931  If not any of above, store element in SearchVector, increment VectorCount, set the new CurrentTrackElement value from the
14932  SearchElement & the new XLinkPos from SearchElement.XLinkPos, then go back to the while loop for the next step in the search.
14933  When return true have 8 items from CheckCount established, only waiting for EXNumber
14934 */
14935 {
14936  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForNonPreferredRoute," + CurrentTrackElement.LogTrack(14) + "," +
14937  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString() + "," + AnsiString(ReqPosRouteID.GetInt()));
14938  int VectorCount = 0;
14939 
14940 // check for a fouled diagonal for first element. Added for v1.3.2
14941  if((CurrentTrackElement.Link[XLinkPos] == 1) || (CurrentTrackElement.Link[XLinkPos] == 3) || (CurrentTrackElement.Link[XLinkPos] == 7) ||
14942  (CurrentTrackElement.Link[XLinkPos] == 9))
14943  {
14944  if(AllRoutes->DiagonalFouledByRouteOrTrain(8, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc, CurrentTrackElement.Link[XLinkPos]))
14945  {
14946  for(int x = 0; x < VectorCount; x++)
14947  SearchVector.erase(SearchVector.end() - 1);
14948  Utilities->CallLogPop(2044);
14949  return false;
14950  }
14951  }
14952 
14953  while(true)
14954  {
14955  if(Track->IsLCBarrierFlashingAtHV(2, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc)) // can't set a route through a flashing barrier
14956  {
14957  for(int x = 0; x < VectorCount; x++)
14958  SearchVector.erase(SearchVector.end() - 1);
14959  Utilities->CallLogPop(1927);
14960  return false;
14961  }
14962  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
14963  {
14964  for(int x = 0; x < VectorCount; x++)
14965  SearchVector.erase(SearchVector.end() - 1);
14966  Utilities->CallLogPop(290);
14967  return false;
14968  }
14969  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
14970  TTrackElement NextTrackElement = Track->TrackElementAt(93, NextPosition);
14971  TPrefDirElement SearchElement(NextTrackElement);
14972  SearchElement.TrackVectorPosition = NextPosition;
14973  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
14974  SearchElement.ELinkPos = NextELinkPos;
14975  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
14976  int NextXLinkPos;
14977  if(SearchElement.ELinkPos == 0)
14978  NextXLinkPos = 1;
14979  if(SearchElement.ELinkPos == 1)
14980  NextXLinkPos = 0;
14981  if(SearchElement.ELinkPos == 2)
14982  NextXLinkPos = 3;
14983  if(SearchElement.ELinkPos == 3)
14984  NextXLinkPos = 2;
14985  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
14986  {
14987  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
14988  // but may be buffers, continuation or gap
14989  SearchElement.XLinkPos = NextXLinkPos;
14990  }
14991 // Now have SpeedTag, HLoc, VLoc, TrackVectorPosition, ELink, ELinkPos, and for non-points XLink & XLinkPos
14992 // can't set XLink or XLinkPos yet if the element is a leading point.
14993 
14994 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
14995  for(unsigned int x = 0; x < SearchVector.size(); x++)
14996  {
14997  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
14998  {
14999  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
15000  // OK if it's a bridge & routes on different tracks
15001  {
15002  for(int x = 0; x < VectorCount; x++)
15003  SearchVector.erase(SearchVector.end() - 1);
15004  Utilities->CallLogPop(291);
15005  return false;
15006  }
15007  }
15008  }
15009 
15010 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
15011  TAllRoutes::TRouteElementPair SecondPair;
15013  Track->TrackElementAt(94, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(95, SearchElement.TrackVectorPosition).VLoc, SecondPair);
15014  if(RoutePair.first > -1)
15015  {
15016  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
15017  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(43, RoutePair.first).GetFixedPrefDirElementAt(64,
15018  RoutePair.second).ELinkPos)))
15019  {
15020  // still OK if start of an expected route
15021  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(4, ReqPosRouteID)) || (RoutePair.second != 0))
15022  {
15023  for(int x = 0; x < VectorCount; x++)
15024  SearchVector.erase(SearchVector.end() - 1);
15025  Utilities->CallLogPop(292);
15026  return false; // only allow for start of an expected route
15027  }
15028  }
15029  }
15030  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
15031  {
15032  // OK if it's a bridge & routes on different tracks
15033  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(44, SecondPair.first).GetFixedPrefDirElementAt(65,
15034  SecondPair.second).ELinkPos)))
15035  {
15036  // still OK if start of an expected route
15037  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(5, ReqPosRouteID)) || (SecondPair.second != 0))
15038  {
15039  for(int x = 0; x < VectorCount; x++)
15040  SearchVector.erase(SearchVector.end() - 1);
15041  Utilities->CallLogPop(293);
15042  return false; // only allow for start of an expected route
15043  }
15044  }
15045  }
15046 
15047 // check if a train on element, unless a bridge & train on different track
15048 // OK of same train as start element - no, drop this
15049 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
15050  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
15051  {
15052  for(int x = 0; x < VectorCount; x++)
15053  SearchVector.erase(SearchVector.end() - 1);
15054  Utilities->CallLogPop(294);
15055  return false;
15056  }
15057  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
15058  {
15059  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeTrackPos01 > -1))
15060  {
15061  for(int x = 0; x < VectorCount; x++)
15062  SearchVector.erase(SearchVector.end() - 1);
15063  Utilities->CallLogPop(295);
15064  return false;
15065  }
15066  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeTrackPos23 > -1))
15067  {
15068  for(int x = 0; x < VectorCount; x++)
15069  SearchVector.erase(SearchVector.end() - 1);
15070  Utilities->CallLogPop(296);
15071  return false;
15072  }
15073  }
15074 
15075 // check for a fouled diagonal (if not leading point - leading point XLink == -1)
15076  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15077  {
15078  if(AllRoutes->DiagonalFouledByRouteOrTrain(3, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15079  {
15080  for(int x = 0; x < VectorCount; x++)
15081  SearchVector.erase(SearchVector.end() - 1);
15082  Utilities->CallLogPop(297);
15083  return false;
15084  }
15085  }
15086 
15087 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
15088 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
15089 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
15091  {
15092  for(int x = 0; x < VectorCount; x++)
15093  SearchVector.erase(SearchVector.end() - 1);
15094  Utilities->CallLogPop(1689);
15095  return false;
15096  }
15097 
15098 // check if found it
15099  if(SearchElement.TrackVectorPosition == RequiredPosition)
15100  {
15101  if(SearchElement.TrackType == Points) // can only happen for platform element in CallingOnAllowed function
15102  {
15103  if((SearchElement.ELinkPos == 1) || (SearchElement.ELinkPos == 3))
15104  SearchElement.XLinkPos = 0; // select the straight track (for the platform)
15105  else
15106  SearchElement.XLinkPos = 1;
15107 // SearchElement.XLink = SearchElement.Link[XLinkPos]; WRONG!! NajamUddin found this error 17/01/11, XLinkPos is the function input parameter, should be SearchElement.XLinkPos
15108  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos]; // corrected for v0.6a
15109  }
15110  SearchVector.push_back(SearchElement);
15111  VectorCount++; // not really needed but include for tidyness
15112  TotalSearchCount++;
15113  Utilities->CallLogPop(298);
15114  return true;
15115  }
15116 // Not the required element - check if a buffer or continuation
15117  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
15118  {
15119  for(int x = 0; x < VectorCount; x++)
15120  SearchVector.erase(SearchVector.end() - 1);
15121  Utilities->CallLogPop(299);
15122  return false;
15123  }
15124 
15125 // check if SearchVector exceeds a size of 150
15126  if(SearchVector.size() > 150)
15127  {
15128  for(int x = 0; x < VectorCount; x++)
15129  SearchVector.erase(SearchVector.end() - 1);
15130  Utilities->CallLogPop(1421);
15131  return false;
15132  }
15133 
15134 // check if reached a leading point
15135  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
15136  {
15137 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
15138  int SearchPos1 = SearchElement.Attribute + 1;
15139  int SearchPos2;
15140  if(SearchPos1 == 2)
15141  SearchPos1++;
15142  if(SearchPos1 == 1)
15143  SearchPos2 = 3;
15144  else
15145  SearchPos2 = 1;
15146 // push element with XLink set to position [SearchPos1]
15147  SearchElement.XLink = SearchElement.Link[SearchPos1];
15148  SearchElement.XLinkPos = SearchPos1;
15149 // check for a fouled diagonal for leading point for XLinkPos == SearchPos1)
15150  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15151  {
15152  if(AllRoutes->DiagonalFouledByRouteOrTrain(4, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15153  {
15154  for(int x = 0; x < VectorCount; x++)
15155  SearchVector.erase(SearchVector.end() - 1);
15156  Utilities->CallLogPop(300);
15157  return false;
15158  }
15159  }
15160  SearchVector.push_back(SearchElement);
15161  VectorCount++;
15162  TotalSearchCount++;
15163 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
15164 // Note that NextTrackElement is the TTrackElement that the TPrefDirElement SearchElement is constructed from. Can't use SearchElement in the
15165 // recursive search as has to be a TTrackElement for non-preferred route searches
15166  if(SearchForNonPreferredRoute(6, NextTrackElement, SearchPos1, RequiredPosition, ReqPosRouteID))
15167  {
15168  Utilities->CallLogPop(301);
15169  return true;
15170  }
15171  else
15172  {
15173 // remove leading point with XLinkPos [SearchPos1]
15174  SearchVector.erase(SearchVector.end() - 1);
15175  VectorCount--;
15176 // push element with XLink set to position [SearchPos2]
15177  SearchElement.XLink = SearchElement.Link[SearchPos2];
15178  SearchElement.XLinkPos = SearchPos2;
15179 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
15180  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15181  {
15182  if(AllRoutes->DiagonalFouledByRouteOrTrain(5, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15183  {
15184  for(int x = 0; x < VectorCount; x++)
15185  SearchVector.erase(SearchVector.end() - 1);
15186  Utilities->CallLogPop(302);
15187  return false;
15188  }
15189  }
15190  SearchVector.push_back(SearchElement);
15191  VectorCount++;
15192  TotalSearchCount++;
15193 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
15194  if(SearchForNonPreferredRoute(7, NextTrackElement, SearchPos2, RequiredPosition, ReqPosRouteID))
15195  {
15196  Utilities->CallLogPop(303);
15197  return true;
15198  }
15199  else
15200  {
15201  for(int x = 0; x < VectorCount; x++)
15202  SearchVector.erase(SearchVector.end() - 1);
15203  Utilities->CallLogPop(304);
15204  return false;
15205  }
15206  }
15207  } // if leading point
15208 // here if ordinary element, push it, inc VectorCount & update CurrentTrackElement
15209 // ready for next element on route
15210  SearchVector.push_back(SearchElement);
15211  VectorCount++;
15212  TotalSearchCount++;
15213  CurrentTrackElement = SearchElement;
15214  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
15215  } // while(true)
15216 }
15217 
15218 // ---------------------------------------------------------------------------
15219 
15221 
15222 /*
15223  This function is developed from ConvertPrefDirSearchVector, to deal with search elements not
15224  having all values set (since not necessarily on PrefDirs).
15225  Enter with SearchVector established, return if empty. The first element may not have its ELink & XLink etc set
15226  (if it was the start), so these are checked first and set if necessary. All elements now have
15227  all but EXNumber set, so the CheckCount is set to 8 to cover all but EXNumber, and that is then set
15228  for all elements (unless validity check fails) and CheckCount incremented. Finally SetRouteSearchVectorGraphics() is called
15229  to set the route colour and direction graphics.
15230 */
15231 
15232 {
15233  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRemainingSearchVectorValues");
15234  if(SearchVector.size() == 0)
15235  {
15236  throw Exception("Error, SearchVector empty");
15237  }
15238 // first SearchElement may have ELink & XLink not set if entered in GetStart.... i.e if it wasn't already in a route
15239 // hence need to examine and update it if necessary
15240  TPrefDirElement SecondElement;
15241 
15242  if(SearchVector.size() > 1) // if search vector only a single element then first element must have been in a route, and in this case
15243  // all data members will have been set in SearchForNonPreferredRoute except for EXNumber.
15244  // need above check or SecondElement will fail
15245  {
15246  SecondElement = SearchVector.at(1);
15247  // SearchVector.at(0) ELink & XLink not set if was first element in route; XLink also not set if was a leading point though can't be for a route
15248  for(int x = 0; x < 4; x++)
15249  {
15250  if(SearchVector.at(0).Conn[x] == SecondElement.TrackVectorPosition)
15251  {
15252  if(SearchVector.at(0).XLink == -1) // i.e. not set
15253  {
15254  SearchVector.at(0).XLink = SearchVector.at(0).Link[x];
15255  SearchVector.at(0).XLinkPos = x;
15256  }
15257  int ELinkPos;
15258  if(SearchVector.at(0).XLinkPos == 0)
15259  ELinkPos = 1; // use actual value rather than 'x' as may be a gap with both ends
15260  // linked to 1st searchvector element, & if XLink was set then x may not correspond
15261  if(SearchVector.at(0).XLinkPos == 1)
15262  ELinkPos = 0;
15263  if(SearchVector.at(0).XLinkPos == 2)
15264  ELinkPos = 3;
15265  if(SearchVector.at(0).XLinkPos == 3)
15266  ELinkPos = 2;
15267  if(SearchVector.at(0).ELink == -1) // because was start element, & can't be points, but could be a gap
15268  {
15269  SearchVector.at(0).ELink = SearchVector.at(0).Link[ELinkPos];
15270  SearchVector.at(0).ELinkPos = ELinkPos;
15271  }
15272  break; // no point going any further
15273  }
15274  }
15275  }
15276  for(unsigned int x = 0; x < SearchVector.size(); x++)
15277  {
15278  SearchVector.at(x).CheckCount = 8; // to account for all but EXNumber
15279 // set EXNumber
15280  if(!(SearchVector.at(x).EntryExitNumber()))
15281  {
15282  throw Exception("Error in EntryExitNumber 3");
15283  }
15284  SearchVector.at(x).CheckCount++;
15285 // all values now incorporated
15286  }
15287 
15288  SetRouteSearchVectorGraphics(5, false, false); // change graphic colour to the route colour
15289 // This function is only called here for nonsignals routes, so AutoSigsFlag & ConsecSignalsRoute both false
15290 // PrefDir is validated in ConvertAndAddNonPreferredRouteSearchVector
15291  Utilities->CallLogPop(305);
15292 }
15293 
15294 // ---------------------------------------------------------------------------
15295 
15297 
15298 /*
15299  This function is very similar to ConvertAndAddPreferredRouteSearchVector except that the route in SearchVector can't be an
15300  AutoSigsRoute.
15301  Action varies depending on whether it is a completely new route, or an extension of an existing route at the
15302  beginning or the end.
15303  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
15304  Check if route end selection is in an existing route (ReqPosRouteID > -1), if so and existing route is non-autosigs
15305  add its elements to the SearchVector then delete the route, decrementing StartSelectionRouteNumber if the RequPosRouteNumber was
15306  less than StartSelectionRouteID. If existing route is AutoSigs then the final search element is dropped from the SearchVector,
15307  since the new route will end adjacent to the AutoSigs route, and the existing route is left as it is.
15308  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
15309  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
15310 
15311  Check if StartSelectionRouteID set (extending an existing route) and if so and if existing route non-autosig, then add the new route
15312  to the existing route (start element not stored in searchvector), call SetRoutePoints & SetRouteSignals for the extended route and return.
15313  If the existing route is autosig, then leave the existing route as it is and continue as for routes that aren't linked to an existing
15314  route at the start.
15315 
15316  Check the validity of the route in SearchVector, and create a new route using StoreOneRoute. Finally call SetRoutePoints & SetRouteSignals
15317  for the new route and return.
15318 */
15319 
15320 {
15321  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddNonPreferredRouteSearchVector," +
15322  AnsiString(ReqPosRouteID.GetInt()));
15323  if(SearchVector.size() < 1)
15324  {
15325  Utilities->CallLogPop(306);
15326  return;
15327  }
15328  PrefDirVector = SearchVector; // this copy is to validate the vector up to this point,
15329  if(!ValidatePrefDir(6))
15330  {
15331  Utilities->CallLogPop(307);
15332  return;
15333  }
15334 
15335  TAllRoutes::TLockedRouteClass LockedRouteObject;
15336 
15338  unsigned int TruncatePrefDirPosition = 0;
15339 
15340  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartSelectionRouteID as would have failed in GetNextRouteElement
15341 /* if have ReqPosRouteID:
15342  if existing route non-autosig, then add the old route to the SearchVector then delete the old route
15343  if existing route autosig, drop the final search element in the new route, leave the existing route as it is,
15344  then enter the new route into the AllRoutesVector
15345 */
15346  {
15348  {
15349  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(46, ReqPosRouteID).PrefDirSize();
15350  x++) // start at 1 as first element already in SearchVector
15351  {
15353  }
15354  // note that route numbers in map adjusted when ReqPos route cleared
15356  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
15357  // set during ClearRouteDuringRouteBuildingAt)
15359  {
15362  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
15363  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
15364  }
15365  }
15367  {
15368  SearchVector.pop_back();
15369  }
15370  }
15371 
15372  if(StartSelectionRouteID > -1)
15373 /* if have StartSelectionRouteID:
15374  if existing route non-autosig, then add the new route to the existing route (start element not stored in searchvector)
15375  if existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
15376 */
15377  {
15379  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
15380  {
15382  {
15383  int RouteNumber = AllRoutes->GetRouteVectorNumber(1, StartSelectionRouteID);
15384  for(unsigned int x = 0; x < SearchVector.size(); x++)
15385  {
15387  RouteNumber, GetFixedSearchElementAt(7, x));
15388  // find & store locked route truncate position in PrefDirVector for later use
15390  {
15391  if(GetFixedSearchElementAt(16, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
15392  {
15393  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(176, RouteNumber).PrefDirSize() - 1;
15394  }
15395  }
15396  }
15398  {
15399  throw Exception("Failed to validate extended route for nonpreferred route");
15400  }
15403  AllRoutes->GetModifiableRouteAtIDNumber(9, StartSelectionRouteID).SetLCChangeValues(2, false); // ConsecSignalsRoute is false
15404  // now add the reinstated locked route if required and set signals accordingly
15405  // shouldn't ever need to access this as the train that has caused the locked route will be ahead of the route to be added,
15406  // and it will have removed the route elements that it is standing on, but include in case there's some obscure condition
15407  // that I haven't thought of
15409  {
15410  LockedRouteObject.RouteNumber = RouteNumber;
15411  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
15412  // now reset the signals for the locked route
15413  AllRoutes->SetAllRearwardsSignals(12, 0, RouteNumber, TruncatePrefDirPosition);
15414  for(int c = AllRoutes->GetFixedRouteAt(177, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
15415  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
15416  // return all signals to red in route section to be truncated
15417  {
15418  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(178, RouteNumber).PrefDirVector.at(c);
15419  TTrackElement & TrackElement = Track->TrackElementAt(813, PrefDirElement.TrackVectorPosition);
15420  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
15421  {
15422  TrackElement.Attribute = 0;
15423  Track->PlotSignal(11, TrackElement, Display);
15424  Display->PlotOutput(115, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
15425  Display->PlotOutput(116, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
15426  }
15427  }
15428  }
15429  AllRoutes->CheckMapAndRoutes(3); // test
15430  Utilities->CallLogPop(308);
15431  return;
15432  }
15433  }
15434  else
15435  {
15437  }
15438 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
15439 // hence nothing to do here
15440  }
15441 
15442  PrefDirVector = SearchVector; // copy again prior to storing as a route as SearchVector may have been extended
15443  if(!ValidatePrefDir(8)) // validate PrefDir for all new route elements
15444  {
15445  throw Exception("Failed to validate single route for nonpreferred route");
15446  }
15447  AllRoutes->StoreOneRoute(2, this);
15448  AllRoutes->GetModifiableRouteAt(6, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(3); // new addition
15449  AllRoutes->GetModifiableRouteAt(17, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(7); // new addition
15450  AllRoutes->GetModifiableRouteAt(19, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(3, false); // ConsecSignalsRoute is false
15451  AllRoutes->CheckMapAndRoutes(4); // test
15452  Utilities->CallLogPop(309);
15453 }
15454 
15455 // ---------------------------------------------------------------------------
15456 
15457 void TOneRoute::SetRoutePoints(int Caller) const
15458 /*
15459  Examine each set of points in the route to see if entry or exit is via the straight or diverging trailing
15460  link, and set the attribute accordingly (don't need to worry about linked routes, points in those will have been set
15461  when they were created.
15462 */
15463 {
15464  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRoutePoints");
15465  if(!PrefDirVector.empty())
15466  {
15467  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
15468  {
15469  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 1) || (PrefDirPtr->XLinkPos == 1))) // 1=straight trailing
15470  {
15471  Track->TrackElementAt(96, PrefDirPtr->TrackVectorPosition).Attribute = 0; // 0=straight
15472  Track->PlotPoints(3, Track->TrackElementAt(97, PrefDirPtr->TrackVectorPosition), Display, false);
15473  }
15474  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 3) || (PrefDirPtr->XLinkPos == 3))) // 3=diverging trailing
15475  {
15476  Track->TrackElementAt(98, PrefDirPtr->TrackVectorPosition).Attribute = 1; // 1=diverging
15477  Track->PlotPoints(4, Track->TrackElementAt(99, PrefDirPtr->TrackVectorPosition), Display, false);
15478  }
15479  }
15480  }
15481  Utilities->CallLogPop(327);
15482 }
15483 
15484 // ---------------------------------------------------------------------------
15485 
15486 void TOneRoute::SetRouteSignals(int Caller) const
15487 /* Used for new train additions in AddTrain and in route setting
15488  Set the signals as follows:-
15489  First check whether there is a linked forward route, and if so use FindForwardTargetSignalAttribute to work along it from the start
15490  until find a train (return Attribute = 0 & NextForwardLinkedRouteNumber = -1), a buffer (return Attribute = 1 &
15491  NextForwardLinkedRouteNumber = -1), a continuation (return Attribute = 3 & NextForwardLinkedRouteNumber = -1) or a forward-facing
15492  signal. If find a signal its attribute value + 1 up to a maximum value of 3 is returned & NextForwardLinkedRouteNumber = -1.
15493  The above Attribute values represent the 'target' attribute, from which all rearwards signals in turn in the new route are set,
15494  the first using the returned attribute value and subsequent ones incrementing the Attribute up to a maximum of 3. All the foregoing
15495  return true, as does finding none of the above and no onward linked forward route (NextForwardLinkedRouteNumber = -1). If none
15496  of the foregoing are found but there is a further forward linked forward route then the function returns false with
15497  NextForwardLinkedRouteNumber = the next forward linked route number, to allow that to be examined similarly, and Attribute = 0.
15498 
15499  When the target Attribute is found (will be 0 if no forward linked route), then SetAllRearwardsSignals is used to work back from
15500  the end of the route setting each forward-facing signal one step nearer green as described above, until either reach the end of all
15501  linked rearwards routes or find a train. If find a train in the current route then signals behind it (and behind any other trains
15502  in the current route) are set appropriately (including in linked rear routes), but if find a train in a linked rear route then no
15503  further signals are set. If there is no forward linked route and the front end of the current route is a buffer then
15504  SetAllRearwardsSignals (in its call to SetRearwardsSignalsReturnFalseForTrain) treats it as a red signal, and if a continuation,
15505  as a green signal.
15506 */
15507 {
15508  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSignals");
15509  if(!PrefDirVector.empty())
15510  {
15511  // get target Attribute value, check first if there is a forward linked route
15512  TPrefDirElement LastElement = GetFixedPrefDirElementAt(185, PrefDirSize() - 1);
15513  TPrefDirElement FirstElement = GetFixedPrefDirElementAt(186, 0);
15514  int ForwardLinkedRouteNumber, Attribute = 0;
15515  if(LastElement.Conn[LastElement.XLinkPos] > -1)
15516  // Note that LastElement can't be points but can be linked to points
15517  {
15518  if(AllRoutes->GetRouteTypeAndNumber(16, LastElement.Conn[LastElement.XLinkPos], LastElement.ConnLinkPos[LastElement.XLinkPos],
15519  ForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
15520  {
15521  if(ForwardLinkedRouteNumber > -1)
15522  {
15523  int NextForwardLinkedRouteNumber = -1;
15524  while(!(AllRoutes->GetFixedRouteAt(171, ForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(1, NextForwardLinkedRouteNumber,
15525  Attribute)))
15526  {
15527  ForwardLinkedRouteNumber = NextForwardLinkedRouteNumber;
15528  }
15529  // if find a train before a signal then Attribute = 0, else if find end of route is a buffer then Attribute = 1, or a continuation then
15530  // Attribute = 3, else if find signal then Attribute = (signal attribute + 1) up to a max value of 3. All these return true, if find a
15531  // forward linked route then the routenumber is set in NextForwardLinkedRouteNumber, Attribute = 0 & returns false.
15532  }
15533  }
15534  }
15535  int RouteNumber;
15536  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(15, GetFixedPrefDirElementAt(187, 0).TrackVectorPosition,
15537  GetFixedPrefDirElementAt(193, 0).XLinkPos, RouteNumber);
15538  if(RouteType != TAllRoutes::NoRoute)
15539  // it will be, above only used to get RouteNumber, can choose any element in the route so use GetFixedPrefDirElementAt
15540  {
15541  AllRoutes->SetAllRearwardsSignals(8, Attribute, RouteNumber, PrefDirSize() - 1);
15542  }
15543  }
15544  Utilities->CallLogPop(1720);
15545 }
15546 
15547 // ---------------------------------------------------------------------------
15548 
15549 bool TOneRoute::PointsToBeChanged(int Caller) const
15550 { // true if at any point in SearchVector points have to be changed
15551  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PointsToBeChanged");
15552  if(!SearchVector.empty())
15553  {
15554  for(TPrefDirVectorConstIterator SearchPtr = SearchVector.begin(); SearchPtr != SearchVector.end(); SearchPtr++)
15555  {
15556  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 1) || (SearchPtr->XLinkPos == 1))) // 1=straight trailing
15557  {
15558  if(Track->TrackElementAt(752, SearchPtr->TrackVectorPosition).Attribute != 0) // 0=straight or LH
15559  {
15560  Utilities->CallLogPop(1717);
15561  return true;
15562  }
15563  }
15564  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 3) || (SearchPtr->XLinkPos == 3))) // 3=diverging trailing
15565  {
15566  if(Track->TrackElementAt(753, SearchPtr->TrackVectorPosition).Attribute != 1) // 1=diverging or RH
15567  {
15568  Utilities->CallLogPop(1718);
15569  return true;
15570  }
15571  }
15572  }
15573  }
15574  Utilities->CallLogPop(1719);
15575  return false;
15576 }
15577 
15578 // ---------------------------------------------------------------------------
15579 
15580 bool TOneRoute::FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
15581 /*
15582  Works forward through the route until finds:-
15583  (a) a train - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
15584  (b) end of route at buffers - Attribute = 1, NextForwardLinkedRouteNumber = -1 & returns true;
15585  (c) end of route at continuation - Attribute = 3, NextForwardLinkedRouteNumber = -1 & returns true;
15586  (d) level crossing with barriers not down - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
15587  (e) forward-facing signal - Attribute = 1 + signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true;
15588  (f) end of route not at any of foregoing and with no linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = -1 &
15589  returns true;
15590  (g) linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = the routenumber of the forward route & returns false.
15591 */
15592 {
15593  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindForwardTargetSignalAttribute");
15594  Attribute = 0;
15595  NextForwardLinkedRouteNumber = -1;
15596  for(unsigned int x = 0; x < PrefDirSize(); x++)
15597  {
15598  int TrainID = Track->TrackElementAt(100, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnElement;
15599  if(PrefDirVector.at(x).TrackType == Bridge)
15600  {
15601  if(PrefDirVector.at(x).XLinkPos < 2)
15602  TrainID = Track->TrackElementAt(101, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeTrackPos01;
15603  else
15604  TrainID = Track->TrackElementAt(102, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeTrackPos23;
15605  }
15606  if(TrainID != -1)
15607  {
15608  Utilities->CallLogPop(328);
15609  return true;
15610  }
15611  if(PrefDirVector.at(x).TrackType == Buffers)
15612  {
15613  Attribute = 1;
15614  Utilities->CallLogPop(329);
15615  return true;
15616  }
15617  if(PrefDirVector.at(x).TrackType == Continuation)
15618  {
15619  Attribute = 3;
15620  Utilities->CallLogPop(330);
15621  return true;
15622  }
15623  if(Track->IsLCAtHV(42, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
15624  {
15625  if(!Track->IsLCBarrierDownAtHV(3, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
15626  {
15627  Attribute = 0;
15628  Utilities->CallLogPop(1950);
15629  return true;
15630  }
15631  }
15632  if(PrefDirVector.at(x).Config[PrefDirVector.at(x).XLinkPos] == Signal)
15633  {
15634  Attribute = Track->TrackElementAt(103, PrefDirVector.at(x).TrackVectorPosition).Attribute + 1;
15635  if(Attribute > 3)
15636  Attribute = 3;
15637  Utilities->CallLogPop(331);
15638  return true;
15639  }
15640  if(x == PrefDirSize() - 1)
15641  {
15642  TPrefDirElement LastElement = PrefDirVector.at(x);
15643  if(LastElement.Conn[LastElement.XLinkPos] > -1)
15644  {
15645  if(AllRoutes->GetRouteTypeAndNumber(2, LastElement.Conn[LastElement.XLinkPos],
15646  Track->GetNonPointsOppositeLinkPos(LastElement.ConnLinkPos[LastElement.XLinkPos]), NextForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
15647  {
15648  Attribute = 0;
15649  Utilities->CallLogPop(332);
15650  return false;
15651  }
15652  }
15653  }
15654  }
15655  Utilities->CallLogPop(333);
15656  return true;
15657 }
15658 
15659 // ---------------------------------------------------------------------------
15660 
15661 bool TOneRoute::SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
15662 /*
15663  This function is only called by TAllRoutes::SetAllRearwardsSignals.
15664 
15665  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
15666  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
15667  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
15668  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
15669  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
15670  a route.
15671 
15672  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
15673  signal. If find a signal (but see note below) set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
15674  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3. On completion Attribute is
15675  passed back from the function as a reference. If no train is found before the beginning of the route is reached the function returns true.
15676 
15677  In setting signals skip the first position if it's a signal and if truncating - otherwise the truncated signal counts as the first red
15678  and the next rearwards signal becomes yellow, although it's the first in the route
15679 */
15680 {
15681  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRearwardsSignalsReturnFalseForTrain," + AnsiString(Attribute) + "," +
15682  AnsiString(PrefDirVectorStartPosition));
15683  Graphics::TBitmap *EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default values
15684  Graphics::TBitmap *EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd;
15685 // if no train between end of route and PrefDirVectorStartPosition, route not in ContinuationAutoSigVector
15686 // & not truncating a route, then Attribute can be modified if end is buffers or continuation
15687  bool SkipContinuationAndBufferAttributeChange = false;
15688 
15689  if(!PrefDirVector.empty())
15690  {
15691  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr < PrefDirVector.end(); PrefDirPtr++)
15692  {
15693  int TrainID = Track->TrackElementAt(104, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
15694  if(PrefDirPtr->TrackType == Bridge)
15695  {
15696  if(PrefDirPtr->XLinkPos < 2)
15697  TrainID = Track->TrackElementAt(105, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos01;
15698  else
15699  TrainID = Track->TrackElementAt(106, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos23;
15700  }
15701  if(TrainID != -1)
15702  {
15703  SkipContinuationAndBufferAttributeChange = true;
15704  break;
15705  }
15706  }
15707 
15710  {
15711  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.begin(); AutoSigVectorIT < TrainController->ContinuationAutoSigVector.end();
15712  AutoSigVectorIT++)
15713  {
15714  if(!AllRoutes->AllRoutesVector.empty())
15715  {
15716  if((&AllRoutes->AllRoutesVector.front() + AutoSigVectorIT->RouteNumber) == this)
15717  {
15718  SkipContinuationAndBufferAttributeChange = true;
15719  break;
15720  }
15721  }
15722  }
15723  }
15724 
15726  SkipContinuationAndBufferAttributeChange = true;
15727 
15728  if(!SkipContinuationAndBufferAttributeChange)
15729  {
15730  if(PrefDirVector.back().TrackType == Buffers)
15731  Attribute = 1; // treat buffer as red signal
15732  if(PrefDirVector.back().TrackType == Continuation)
15733  Attribute = 3; // treat continuation as a green signal
15734  }
15735 
15736  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
15737  {
15738  int TrainID = Track->TrackElementAt(107, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
15739  if(PrefDirPtr->TrackType == Bridge)
15740  {
15741  if(PrefDirPtr->XLinkPos < 2)
15742  TrainID = Track->TrackElementAt(108, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos01;
15743  else
15744  TrainID = Track->TrackElementAt(109, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos23;
15745  }
15746  if(TrainID != -1)
15747  {
15748  Utilities->CallLogPop(334);
15749  return false;
15750  }
15751  // if find an LC that is closed to trains (or flashing - may be extending an earlier route with flashing LCs) then reset
15752  // the attribute to 0 so first signal behind the LC is red
15753  if(Track->IsLCAtHV(20, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
15754  {
15755  if(!Track->IsLCBarrierDownAtHV(1, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
15756  {
15757  Attribute = 0;
15758  }
15759  }
15760 // now set signals, but skip the first position if it's a signal on an unrestricted route and truncating - otherwise the truncated signal
15761 // counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
15762  if(PrefDirPtr->Config[PrefDirPtr->XLinkPos] == Signal)
15763  {
15764  if((!AllRoutes->RouteTruncateFlag) || (PrefDirPtr != (PrefDirVector.begin() + PrefDirVectorStartPosition)) || PrefDirPtr->AutoSignals ||
15765  PrefDirPtr->ConsecSignals)
15766  {
15767  if(Attribute < 3)
15768  Track->TrackElementAt(110, PrefDirPtr->TrackVectorPosition).Attribute = Attribute;
15769  else
15770  Track->TrackElementAt(111, PrefDirPtr->TrackVectorPosition).Attribute = 3; // green
15771  Track->PlotSignal(1, Track->TrackElementAt(112, PrefDirPtr->TrackVectorPosition), Display);
15772  if(AllRoutes->GetRouteTypeAndGraphics(1, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, EXGraphicPtr,
15773  EntryDirectionGraphicPtr) != TAllRoutes::NoRoute)
15774  {
15775  Display->PlotOutput(16, Track->TrackElementAt(113, PrefDirPtr->TrackVectorPosition).HLoc * 16,
15776  Track->TrackElementAt(114, PrefDirPtr->TrackVectorPosition).VLoc * 16, EXGraphicPtr);
15777  Display->PlotOutput(17, Track->TrackElementAt(115, PrefDirPtr->TrackVectorPosition).HLoc * 16,
15778  Track->TrackElementAt(116, PrefDirPtr->TrackVectorPosition).VLoc * 16, EntryDirectionGraphicPtr);
15779  }
15780  if(Attribute < 3)
15781  Attribute++;
15782  Display->Update(); // update after recent plots
15783  }
15784  }
15785  }
15786  }
15787  Utilities->CallLogPop(335);
15788  return true;
15789 }
15790 
15791 // ---------------------------------------------------------------------------
15792 
15793 void TOneRoute::GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, TTruncateReturnType &ReturnFlag)
15794 /*
15795  Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFlag value of NotInRoute.
15796  If it is in a route but the element selected is invalid, then a message is given and returns with a ReturnFlag value of
15797  InRouteFalse. Otherwise the route is truncated at and including the element that matches H & V with a ReturnFlag value of InRouteTrue.
15798  Selection invalid if a train at or before the truncate point; select a bridge; trying to leave a single element; last element to be left
15799  not a signal (for ConsecSignalsRoute or has AutoSigsFlag set); last element to be left a bridge, points or crossover (for not
15800  ConsecSignalsRoute & AutoSigsFlag not set), or part of route locked. Check if a train approaching or occupying route and lock route
15801  if required after offering the user the choice to continue or not. Then SetAllRearwardsSignals is called to set signals before the
15802  truncate point, beginning with a red signal, and RemoveRouteElement called for all elements from the end to and including the truncate point.
15803 */
15804 {
15805  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
15806  "," + AnsiString((short)ConsecSignalsRoute));
15807  bool ElementInRoute = false;
15808  bool TrainOccupyingRoute = false;
15809 
15810  for(unsigned int b = 0; b < PrefDirSize(); b++)
15811  {
15812  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
15813  {
15814  ElementInRoute = true;
15815  break;
15816  }
15817  }
15818  if(!ElementInRoute)
15819  {
15820  ReturnFlag = NotInRoute;
15821  Utilities->CallLogPop(336);
15822  return;
15823  }
15824 // it is in the route so continue, first look for a train or a flashing level crossing
15825  for(int b = PrefDirSize() - 1; b >= 0; b--)
15826  {
15827  int TrainID = Track->TrackElementAt(117, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
15828  if(PrefDirVector.at(b).TrackType == Bridge)
15829  {
15830  if(PrefDirVector.at(b).XLinkPos < 2)
15831  TrainID = Track->TrackElementAt(118, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeTrackPos01;
15832  else
15833  TrainID = Track->TrackElementAt(119, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeTrackPos23;
15834  }
15835  if(TrainID != -1)
15836  {
15837 // TrainController->StopTTClockMessage(56, "Can't truncate a route that is occupied by a train");
15838 // ReturnFlag = InRouteFalse;
15839 // Utilities->CallLogPop(337);
15840 // return;
15841 // above removed at v2.1.0 so that routes can be locked when occupied, below added
15842  TrainOccupyingRoute = true; // train is forward of the truncate point
15843  }
15844  if(Track->IsLCBarrierFlashingAtHV(3, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
15845  {
15846  TrainController->StopTTClockMessage(79, "Can't cancel a route containing a level crossing that is changing state");
15847  ReturnFlag = InRouteFalse;
15848  Utilities->CallLogPop(1941);
15849  return;
15850  }
15851  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
15852  {
15853  break; // OK found truncate element & no flashing LC in front
15854  }
15855  }
15856 
15857  for(unsigned int b = 0; b < PrefDirSize(); b++)
15858  {
15859  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc)) // b = the truncate point
15860  {
15861  if(PrefDirVector.at(b).TrackType == Bridge)
15862  {
15863  TrainController->StopTTClockMessage(57, "Can't select a bridge as a route truncate point");
15864  ReturnFlag = InRouteFalse;
15865  Utilities->CallLogPop(338);
15866  return;
15867  }
15868  if(b == 1)
15869  {
15870  TrainController->StopTTClockMessage(58, "Can't truncate to a single route element");
15871  ReturnFlag = InRouteFalse;
15872  Utilities->CallLogPop(339);
15873  return;
15874  }
15875  if(b > 0)
15876  {
15877  TPrefDirElement TempElement = PrefDirVector.at(b - 1);
15878  if(TempElement.ConsecSignals || TempElement.AutoSignals)
15879  {
15880  if(TempElement.Config[TempElement.XLinkPos] != Signal)
15881  {
15882  TrainController->StopTTClockMessage(59, "Must truncate to a valid signal - select position after signal");
15883  ReturnFlag = InRouteFalse;
15884  Utilities->CallLogPop(340);
15885  return;
15886  }
15887  }
15888  else
15889  {
15890  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
15891  {
15892  TrainController->StopTTClockMessage(60, "Can't truncate to points, bridge or crossover");
15893  ReturnFlag = InRouteFalse;
15894  Utilities->CallLogPop(341);
15895  return;
15896  }
15897  }
15898  }
15899 
15900  int RouteNumber;
15902 // Have to call RouteLockingRequired before SetAllRearwardsSignals because RouteLockingRequired tests the first rearward signal, if it is
15903 // red then locking is not required, and if call SetAllRearwardsSignals first then it will set the first rearward signal to red.
15904 
15905 // check if part of this route already locked & disallow if so
15906  if(!(AllRoutes->LockedRouteVector.empty()))
15907  {
15909  {
15910  if(LRVIT->RouteNumber == RouteNumber)
15911  {
15912  TrainController->StopTTClockMessage(61, "Can't truncate a route that is already part-locked");
15913  ReturnFlag = InRouteFalse;
15914  Utilities->CallLogPop(749);
15915  return;
15916  }
15917  }
15918  }
15919 
15920  if(AllRoutes->RouteLockingRequired(0, RouteNumber, b) || TrainOccupyingRoute) // added TrainOccupyingRoute at v2.1.0,
15921  // RouteLockingRequired only checks for trains approaching
15922  {
15925  int button = Application->MessageBox(L"Train approaching or occupying route, YES to lock route (2 minutes to release), NO to cancel",
15926  L"Warning!", MB_YESNO | MB_ICONWARNING);
15927  TrainController->BaseTime = TDateTime::CurrentDateTime();
15929  if(button == IDNO)
15930  {
15931  ReturnFlag = InRouteTrue; // still return true even though don't act on it
15932  Utilities->CallLogPop(342);
15933  return;
15934  }
15935  AnsiString LocID = AnsiString(Track->TrackElementAt(534, PrefDirVector.at(b).TrackVectorPosition).ElementID);
15936  TrainController->LogActionError(0, "", "", FailLockedRoute, LocID);
15937  TAllRoutes::TLockedRouteClass LockedRoute;
15938  bool ExistingLockedRouteModified = false;
15939  LockedRoute.RouteNumber = RouteNumber;
15940  LockedRoute.TruncateTrackVectorPosition = PrefDirVector.at(b).TrackVectorPosition;
15941  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
15942  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
15943  LockedRoute.LockStartTime = TrainController->TTClockTime;
15944 // but first check if this route already in LockedRouteVector (i.e. locked further along), and if so just change that vector entry
15945 // to use the new TruncateTrackVectorPosition & LockStartTime
15946  if(!AllRoutes->LockedRouteVector.empty())
15947  {
15948  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.begin(); LRVIT < AllRoutes->LockedRouteVector.end();
15949  LRVIT++)
15950  {
15951  if(LRVIT->RouteNumber == RouteNumber)
15952  {
15953  LRVIT->TruncateTrackVectorPosition = LockedRoute.TruncateTrackVectorPosition;
15954  LRVIT->LockStartTime = LockedRoute.LockStartTime;
15955  ExistingLockedRouteModified = true;
15956  }
15957  }
15958  }
15959  if(!ExistingLockedRouteModified)
15960  AllRoutes->LockedRouteVector.push_back(LockedRoute);
15961  AllRoutes->SetAllRearwardsSignals(2, 0, RouteNumber, b);
15962  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
15963  // return all signals to red in route section to be truncated
15964  {
15965  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(61, RouteNumber).PrefDirVector.at(c);
15966  TTrackElement & TrackElement = Track->TrackElementAt(120, PrefDirElement.TrackVectorPosition);
15967  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
15968  {
15969  TrackElement.Attribute = 0;
15970  Track->PlotSignal(2, TrackElement, Display);
15971  Display->PlotOutput(18, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
15972  Display->PlotOutput(19, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
15973  }
15974  }
15975 // Display->Update();//not needed as Clearand... called on return from GetAllRoutesTruncateElement in InterfaceUnit
15976  ReturnFlag = InRouteTrue;
15977  }
15978  else
15979  {
15980  AllRoutes->SetAllRearwardsSignals(3, 0, RouteNumber, b);
15981  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
15982  {
15983  AllRoutes->RemoveRouteElement(5, LastElementPtr(3)->HLoc, LastElementPtr(4)->VLoc, LastElementPtr(5)->ELink);
15984  ReturnFlag = InRouteTrue;
15985  }
15986  }
15987  AllRoutes->CheckMapAndRoutes(5); // test
15988  Utilities->CallLogPop(343);
15989  return;
15990  }
15991  }
15992  ReturnFlag = NotInRoute;
15993  Utilities->CallLogPop(344);
15994 }
15995 
15996 // ---------------------------------------------------------------------------
15998 /*
15999  This is used when a train enters a route set in the opposite direction of travel (or at a crossover on a non-route line when the other
16000  track is in a route). The complete route is cancelled (but not linked routes), and all signals in the route are set to red.
16001  First all signals are set to red and replotted (without any route colours), then SetAllRearwardsSignals is called from the
16002  beginning of the route to set all linked rearwards route signals appropriately. Then all elements are removed from the route
16003  and RebuildRailwayFlag set (examined in Interface unit at each clock tick) to force a ClearandRebuildRailway to get rid of
16004  the route colours.
16005 */
16006 {
16007  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ForceCancelRoute");
16008  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
16010  int RouteNumber;
16011  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(4, GetFixedPrefDirElementAt(86, 0).TrackVectorPosition,
16012  GetFixedPrefDirElementAt(87, 0).XLinkPos, RouteNumber);
16013 
16014  if(RouteType != TAllRoutes::NoRoute) // it won't be, above only used to get RouteNumber for setting rearwards signals
16015  {
16016  for(unsigned int x = 0; x < PrefDirSize(); x++) // set all signals in route to red regardless of direction
16017  {
16018  if(PrefDirVector.at(x).TrackType == SignalPost)
16019  {
16020  Track->TrackElementAt(121, PrefDirVector.at(x).TrackVectorPosition).Attribute = 0; // red
16021  Track->PlotSignal(3, Track->TrackElementAt(122, PrefDirVector.at(x).TrackVectorPosition), Display);
16022  }
16023  }
16024  AllRoutes->SetAllRearwardsSignals(4, 0, RouteNumber, 0);
16025 // already set all signals to red in route so start at start of route for further rearwards signal setting
16026  }
16027  for(int c = PrefDirSize() - 1; c >= 0; c--) // must use int for >= test to succeed when b == 0
16028  {
16029  AllRoutes->RemoveRouteElement(6, LastElementPtr(6)->HLoc, LastElementPtr(7)->VLoc, LastElementPtr(8)->ELink);
16030  }
16031  AllRoutes->RebuildRailwayFlag = true; // set to force a ClearandRebuildRailway at next clock tick if not in zoom-out mode
16032  AllRoutes->CheckMapAndRoutes(9); // test
16033  TrainController->BaseTime = TDateTime::CurrentDateTime();
16035  Utilities->CallLogPop(345);
16036  return;
16037 }
16038 
16039 // ---------------------------------------------------------------------------
16040 
16041 void TOneRoute::SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool ConsecSignalsRoute)
16042 /*
16043  Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector.
16044 */
16045 {
16046  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSearchVectorGraphics," + AnsiString((short)AutoSigsFlag) + "," +
16047  AnsiString((short)ConsecSignalsRoute));
16048  if(SearchVector.empty())
16049  {
16050  Utilities->CallLogPop(1149);
16051  return;
16052  }
16053  for(unsigned int b = 0; b < SearchVector.size(); b++)
16054  {
16055  GetModifiableSearchElementAt(1, b).EXGraphicPtr = GetModifiableSearchElementAt(2, b).GetRouteGraphicPtr(AutoSigsFlag, ConsecSignalsRoute);
16057  ConsecSignalsRoute);
16058  }
16059  Utilities->CallLogPop(346);
16060 }
16061 
16062 // ---------------------------------------------------------------------------
16063 
16064 void TOneRoute::SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool ConsecSignalsRoute)
16065 /*
16066  Sets all element values in the RouteFlashVector (member of class TRouteFlash - defined in TOneRoute, of which
16067  TOneRoute has one member called RouteFlash) from the SearchVector. TRouteFlashElement is also a class defined in
16068  TOneRoute.
16069 */
16070 {
16071  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteAndLCChangeValues," + AnsiString((short)AutoSigsFlag) + "," +
16072  AnsiString((short)ConsecSignalsRoute));
16073  RouteFlash.RouteFlashVector.clear();
16074  TRouteFlashElement RouteFlashElement;
16075 
16076  for(unsigned int b = 0; b < SearchVector.size(); b++)
16077  {
16078  int H = GetFixedSearchElementAt(11, b).HLoc;
16079  int V = GetFixedSearchElementAt(12, b).VLoc;
16081  RouteFlashElement.OverlayGraphic = GetModifiableSearchElementAt(6, b).GetRouteGraphicPtr(AutoSigsFlag, ConsecSignalsRoute);
16082  RouteFlashElement.HLoc = H;
16083  RouteFlashElement.VLoc = V;
16085  RouteFlash.RouteFlashVector.push_back(RouteFlashElement);
16086  }
16087  Utilities->CallLogPop(348);
16088 }
16089 
16090 // ---------------------------------------------------------------------------
16091 
16092 void TOneRoute::SetLCChangeValues(int Caller, bool ConsecSignalsRoute) //used when setting routes to start any included LC's lowering
16093 {
16094  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCChangeValues," + AnsiString((short)ConsecSignalsRoute));
16095  if(!PrefDirVector.empty())
16096  {
16097  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
16098  {
16099  int H = PrefDirPtr->HLoc;
16100  int V = PrefDirPtr->VLoc;
16101  // check for any LCs that are closed to trains & set the flash values and store in the vector
16102  if(Track->IsLCAtHV(39, H, V))
16103  {
16104  if(Track->IsLCBarrierUpAtHV(0, H, V))
16105  {
16106  Track->LCChangeFlag = true;
16107  TTrack::TActiveLevelCrossing CLC; // constructor sets ReducedTimePenalty to false
16108  CLC.HLoc = H;
16109  CLC.VLoc = V;
16111  CLC.BaseElementSpeedTag = PrefDirPtr->SpeedTag;
16114  CLC.ConsecSignals = ConsecSignalsRoute;
16115  Track->SetLinkedLevelCrossingBarrierAttributes(1, H, V, 2); // set attr to 2 for changing state
16116  Track->ChangingLCVector.push_back(CLC);
16117  }
16118  }
16119  }
16120  }
16121  Utilities->CallLogPop(1948);
16122 }
16123 
16124 // ---------------------------------------------------------------------------
16125 
16127 /*
16128  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
16129  checks first whether the OverlayPlotted flag is set and if not plots the OverlayGraphic for all
16130  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
16131  is set. The OverlayGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
16132 */
16133 {
16134  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOverlay");
16135  if(!OverlayPlotted)
16136  {
16137  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
16138  {
16139  if(Track->TrackElementAt(123, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
16140  continue;
16141  Display->PlotOutput(20, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OverlayGraphic);
16142  Display->Update();
16143  }
16144  OverlayPlotted = true;
16145  }
16146  Utilities->CallLogPop(349);
16147 }
16148 
16149 // ---------------------------------------------------------------------------
16150 
16152 /*
16153  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
16154  checks first whether the OverlayPlotted flag is set and if so plots the OriginalGraphic for all
16155  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
16156  is reset. The OriginalGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
16157 */
16158 {
16159  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOriginal");
16160  if(OverlayPlotted)
16161  {
16162  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
16163  {
16164  if(Track->TrackElementAt(124, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
16165  continue;
16166  Display->PlotOutput(21, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OriginalGraphic);
16167  Display->Update();
16168  }
16169  OverlayPlotted = false;
16170  }
16171  Utilities->CallLogPop(350);
16172 }
16173 
16174 // ---------------------------------------------------------------------------
16175 
16176 const TOneRoute &TAllRoutes::GetFixedRouteAt(int Caller, int At) const
16177 {
16178  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAt," + AnsiString(At));
16179  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
16180  {
16181  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetFixedRouteAt");
16182  }
16183  Utilities->CallLogPop(120);
16184  return AllRoutesVector.at(At);
16185 }
16186 
16187 // ---------------------------------------------------------------------------
16188 // ---------------------------------------------------------------------------
16189 
16191 {
16192  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteAt," + AnsiString(At));
16193  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
16194  {
16195  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableRouteAt");
16196  }
16197  Utilities->CallLogPop(121);
16198  return AllRoutesVector.at(At);
16199 }
16200 
16201 // ---------------------------------------------------------------------------
16202 
16203 void TAllRoutes::MarkAllRoutes(int Caller, TDisplay *Disp)
16204 /*
16205  Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir false.
16206 */
16207 {
16208  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkAllRoutes");
16209  for(unsigned int a = 0; a < AllRoutesSize(); a++)
16210  {
16211  GetFixedRouteAt(62, a).PrefDirMarker(7, RouteCall, false, Disp);
16212  }
16213  Utilities->CallLogPop(351);
16214 }
16215 
16216 // ---------------------------------------------------------------------------
16217 
16218 void TAllRoutes::WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
16219 {
16220  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteAllRoutesToImage");
16221  for(unsigned int a = 0; a < AllRoutesSize(); a++)
16222  {
16223  GetFixedRouteAt(166, a).RouteImageMarker(0, Bitmap);
16224  }
16225  Utilities->CallLogPop(1706);
16226 }
16227 
16228 // ---------------------------------------------------------------------------
16229 
16230 bool TAllRoutes::GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute)
16231 /*
16232  Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is present in
16233  that route. The ReturnFlag value indicates InRouteTrue (success), InRouteFalse (failure), or NotInRoute.
16234  Messages are given in GetRouteTruncateElement. If successful the route is truncated at and including
16235  the element that matches H & V. If ConsecSignalsRoute ensure only truncate to a signal, else prevent
16236  truncation to a crossover, bridge or points, also prevent route being left less than 2 elements in
16237  length (train length).
16238 */
16239 {
16240  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAllRoutesTruncateElement," + AnsiString(HLoc) + "," +
16241  AnsiString(VLoc) + "," + AnsiString((short)ConsecSignalsRoute));
16242  for(unsigned int a = 0; a < AllRoutesSize(); a++)
16243  {
16244  TTruncateReturnType ReturnFlag;
16245  RouteTruncateFlag = true;
16246 // used in SetRearwardsSignalsReturnFalseForTrain (called by GetRouteTruncateElement) to skip continuation & buffer attribute change
16247  GetModifiableRouteAt(7, a).GetRouteTruncateElement(0, HLoc, VLoc, ConsecSignalsRoute, ReturnFlag);
16248  RouteTruncateFlag = false;
16249  if(ReturnFlag == NotInRoute)
16250  continue;
16251  else if(ReturnFlag == InRouteTrue)
16252  {
16253  Utilities->CallLogPop(352);
16254  return true;
16255  }
16256  else if(ReturnFlag == InRouteFalse)
16257  {
16258  Utilities->CallLogPop(353);
16259  return false;
16260  }
16261  }
16262  Utilities->CallLogPop(354);
16263  return false;
16264 }
16265 
16266 // ---------------------------------------------------------------------------
16267 
16268 bool TAllRoutes::TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
16269 /*
16270  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)
16271  is found it returns true (for crossovers & points returns true whichever track the route is on), else returns false.
16272 */
16273 {
16274  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackIsInARoute," + AnsiString(TrackVectorPosition) + "," +
16275  AnsiString(LinkPos));
16276  if(TrackVectorPosition == -1) // allows for continuation entries & exits
16277  {
16278  Utilities->CallLogPop(355);
16279  return false;
16280  }
16281  THVPair Route2MultiMapKeyPair;
16282 
16283  Route2MultiMapKeyPair.first = Track->TrackElementAt(125, TrackVectorPosition).HLoc;
16284  Route2MultiMapKeyPair.second = Track->TrackElementAt(126, TrackVectorPosition).VLoc;
16285  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
16286  TRoute2MultiMapIterator Route2MultiMapIterator;
16287 
16288  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0) // none found
16289  {
16290  Utilities->CallLogPop(356);
16291  return false;
16292  }
16293  if(Track->TrackElementAt(706, TrackVectorPosition).TrackType != Bridge) // if not a bridge doesn't matter which track the route is on
16294  {
16295  Utilities->CallLogPop(1422);
16296  return true;
16297  }
16298  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
16299  {
16300  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
16301 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
16302 // realised after writing this that can't be points as would have been covered above, but leave anyway
16303  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(64, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(88,
16304  Route2MultiMapIterator->second.second);
16305  EntryLinkPos = PrefDirElement1.ELinkPos;
16306  ExitLinkPos = PrefDirElement1.XLinkPos;
16307  EntryLink = PrefDirElement1.Link[EntryLinkPos];
16308  ExitLink = PrefDirElement1.Link[ExitLinkPos];
16309  if(EntryLink == Track->TrackElementAt(127, TrackVectorPosition).Link[LinkPos])
16310  {
16311  Utilities->CallLogPop(357);
16312  return true;
16313  }
16314  if(ExitLink == Track->TrackElementAt(128, TrackVectorPosition).Link[LinkPos])
16315  {
16316  Utilities->CallLogPop(358);
16317  return true;
16318  }
16319  }
16320  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2) // if both tracks in route then must return true
16321  {
16322  Utilities->CallLogPop(1423);
16323  return true;
16324  }
16325  Utilities->CallLogPop(363);
16326  return false; // none found
16327 }
16328 
16329 // ---------------------------------------------------------------------------
16330 
16331 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap* &EXGraphicPtr,
16332  Graphics::TBitmap* &EntryDirectionGraphicPtr)
16333 /*
16334  Examines Route2MultiMap and if finds the element at TrackVectorPosition with LinkPos (can be entry or exit) returns the appropriate route
16335  type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute. If element not found then NoRoute is returned. If element is in a route then the EXGraphicPtr
16336  is returned, and if either the start or end of a route then the correct EntryDirectionGraphicPtr is returned, else a transparent element is returned.
16337  Function is used in TrainUnit for retaining AutoSigsRoutes but erasing others after train passes, and for picking up the correct background graphics
16338  for replotting of AutoSigsRoutes.
16339 */
16340 {
16341  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndGraphics," + AnsiString(TrackVectorPosition) + "," +
16342  AnsiString(LinkPos));
16343  EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
16344  EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
16345  if(TrackVectorPosition == -1)
16346  {
16347  Utilities->CallLogPop(364);
16348  return NoRoute; // allows for continuation entries & exits
16349  }
16350  THVPair Route2MultiMapKeyPair;
16351 
16352  Route2MultiMapKeyPair.first = Track->TrackElementAt(133, TrackVectorPosition).HLoc;
16353  Route2MultiMapKeyPair.second = Track->TrackElementAt(134, TrackVectorPosition).VLoc;
16354  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
16355  TRoute2MultiMapIterator Route2MultiMapIterator;
16356 
16357  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
16358  {
16359  Utilities->CallLogPop(365);
16360  return NoRoute; // none found
16361  }
16362  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
16363  {
16364  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
16365 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
16366  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(73, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(97,
16367  Route2MultiMapIterator->second.second);
16368  EntryLinkPos = PrefDirElement1.ELinkPos;
16369  ExitLinkPos = PrefDirElement1.XLinkPos;
16370  EntryLink = PrefDirElement1.Link[EntryLinkPos];
16371  ExitLink = PrefDirElement1.Link[ExitLinkPos];
16372  if(EntryLink == Track->TrackElementAt(135, TrackVectorPosition).Link[LinkPos])
16373  {
16374  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
16375  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(74,
16376  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
16377  {
16378  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
16379  }
16380  if(PrefDirElement1.AutoSignals)
16381  {
16382  Utilities->CallLogPop(366);
16383  return AutoSigsRoute;
16384  }
16385  else
16386  {
16387  Utilities->CallLogPop(367);
16388  return NotAutoSigsRoute;
16389  }
16390  }
16391  if(ExitLink == Track->TrackElementAt(136, TrackVectorPosition).Link[LinkPos])
16392  {
16393  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
16394  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(75,
16395  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
16396  {
16397  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
16398  }
16399  if(PrefDirElement1.AutoSignals)
16400  {
16401  Utilities->CallLogPop(368);
16402  return AutoSigsRoute;
16403  }
16404  else
16405  {
16406  Utilities->CallLogPop(369);
16407  return NotAutoSigsRoute;
16408  }
16409  }
16410  }
16411  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
16412  {
16413  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
16414  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
16415 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
16416  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(76, ItPair.first->second.first).GetFixedPrefDirElementAt(98, ItPair.first->second.second);
16417  EntryLinkPos = PrefDirElement2.ELinkPos;
16418  ExitLinkPos = PrefDirElement2.XLinkPos;
16419  EntryLink = PrefDirElement2.Link[EntryLinkPos];
16420  ExitLink = PrefDirElement2.Link[ExitLinkPos];
16421  if(EntryLink == Track->TrackElementAt(137, TrackVectorPosition).Link[LinkPos])
16422  {
16423  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
16424  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(77, ItPair.first->second.first).PrefDirSize() - 1))
16425  {
16426  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
16427  }
16428  if(PrefDirElement2.AutoSignals)
16429  {
16430  Utilities->CallLogPop(370);
16431  return AutoSigsRoute;
16432  }
16433  else
16434  {
16435  Utilities->CallLogPop(371);
16436  return NotAutoSigsRoute;
16437  }
16438  }
16439  if(ExitLink == Track->TrackElementAt(138, TrackVectorPosition).Link[LinkPos])
16440  {
16441  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
16442  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(78, ItPair.first->second.first).PrefDirSize() - 1))
16443  {
16444  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
16445  }
16446  if(PrefDirElement2.AutoSignals)
16447  {
16448  Utilities->CallLogPop(372);
16449  return AutoSigsRoute;
16450  }
16451  else
16452  {
16453  Utilities->CallLogPop(373);
16454  return NotAutoSigsRoute;
16455  }
16456  }
16457 
16458  ItPair.second--; // the second iterator points one past the last matching value
16459  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(79, ItPair.second->second.first).GetFixedPrefDirElementAt(99, ItPair.second->second.second);
16460  EntryLinkPos = PrefDirElement3.ELinkPos;
16461  ExitLinkPos = PrefDirElement3.XLinkPos;
16462  EntryLink = PrefDirElement3.Link[EntryLinkPos];
16463  ExitLink = PrefDirElement3.Link[ExitLinkPos];
16464  if(EntryLink == Track->TrackElementAt(139, TrackVectorPosition).Link[LinkPos])
16465  {
16466  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
16467  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(80, ItPair.second->second.first).PrefDirSize() - 1))
16468  {
16469  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
16470  }
16471  if(PrefDirElement3.AutoSignals)
16472  {
16473  Utilities->CallLogPop(374);
16474  return AutoSigsRoute;
16475  }
16476  else
16477  {
16478  Utilities->CallLogPop(375);
16479  return NotAutoSigsRoute;
16480  }
16481  }
16482  if(ExitLink == Track->TrackElementAt(140, TrackVectorPosition).Link[LinkPos])
16483  {
16484  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
16485  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(81, ItPair.second->second.first).PrefDirSize() - 1))
16486  {
16487  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
16488  }
16489  if(PrefDirElement3.AutoSignals)
16490  {
16491  Utilities->CallLogPop(376);
16492  return AutoSigsRoute;
16493  }
16494  else
16495  {
16496  Utilities->CallLogPop(377);
16497  return NotAutoSigsRoute;
16498  }
16499  }
16500  }
16501  Utilities->CallLogPop(378);
16502  return NoRoute; // none found
16503 }
16504 
16505 // ---------------------------------------------------------------------------
16506 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
16507 /*
16508  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit) is found returns the appropriate
16509  route type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute and number.
16510 */
16511 {
16512  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndNumber," + AnsiString(TrackVectorPosition) + "," +
16513  AnsiString(LinkPos));
16514  if(TrackVectorPosition == -1)
16515  {
16516  RouteNumber = -1;
16517  Utilities->CallLogPop(379);
16518  return NoRoute; // allows for continuation & buffer entries & exits
16519  }
16520  THVPair Route2MultiMapKeyPair;
16521 
16522  Route2MultiMapKeyPair.first = Track->TrackElementAt(141, TrackVectorPosition).HLoc;
16523  Route2MultiMapKeyPair.second = Track->TrackElementAt(142, TrackVectorPosition).VLoc;
16524  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
16525  TRoute2MultiMapIterator Route2MultiMapIterator;
16526 
16527  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
16528  {
16529  RouteNumber = -1;
16530  Utilities->CallLogPop(380);
16531  return NoRoute; // none found
16532  }
16533  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
16534  {
16535  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
16536 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
16537  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(82, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(100,
16538  Route2MultiMapIterator->second.second);
16539  EntryLinkPos = PrefDirElement1.ELinkPos;
16540  ExitLinkPos = PrefDirElement1.XLinkPos;
16541  EntryLink = PrefDirElement1.Link[EntryLinkPos];
16542  ExitLink = PrefDirElement1.Link[ExitLinkPos];
16543  if(EntryLink == Track->TrackElementAt(143, TrackVectorPosition).Link[LinkPos])
16544  {
16545  RouteNumber = Route2MultiMapIterator->second.first;
16546  if(PrefDirElement1.AutoSignals)
16547  {
16548  Utilities->CallLogPop(381);
16549  return AutoSigsRoute;
16550  }
16551  else
16552  {
16553  Utilities->CallLogPop(382);
16554  return NotAutoSigsRoute;
16555  }
16556  }
16557  if(ExitLink == Track->TrackElementAt(144, TrackVectorPosition).Link[LinkPos])
16558  {
16559  RouteNumber = Route2MultiMapIterator->second.first;
16560  if(PrefDirElement1.AutoSignals)
16561  {
16562  Utilities->CallLogPop(383);
16563  return AutoSigsRoute;
16564  }
16565  else
16566  {
16567  Utilities->CallLogPop(384);
16568  return NotAutoSigsRoute;
16569  }
16570  }
16571  }
16572  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
16573  {
16574  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
16575  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
16576 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
16577  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(83, ItPair.first->second.first).GetFixedPrefDirElementAt(101, ItPair.first->second.second);
16578  EntryLinkPos = PrefDirElement2.ELinkPos;
16579  ExitLinkPos = PrefDirElement2.XLinkPos;
16580  EntryLink = PrefDirElement2.Link[EntryLinkPos];
16581  ExitLink = PrefDirElement2.Link[ExitLinkPos];
16582  if(EntryLink == Track->TrackElementAt(145, TrackVectorPosition).Link[LinkPos])
16583  {
16584  RouteNumber = ItPair.first->second.first;
16585  if(PrefDirElement2.AutoSignals)
16586  {
16587  Utilities->CallLogPop(385);
16588  return AutoSigsRoute;
16589  }
16590  else
16591  {
16592  Utilities->CallLogPop(386);
16593  return NotAutoSigsRoute;
16594  }
16595  }
16596  if(ExitLink == Track->TrackElementAt(146, TrackVectorPosition).Link[LinkPos])
16597  {
16598  RouteNumber = ItPair.first->second.first;
16599  if(PrefDirElement2.AutoSignals)
16600  {
16601  Utilities->CallLogPop(387);
16602  return AutoSigsRoute;
16603  }
16604  else
16605  {
16606  Utilities->CallLogPop(388);
16607  return NotAutoSigsRoute;
16608  }
16609  }
16610 
16611  ItPair.second--; // the second iterator points one past the last matching value
16612  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(84, ItPair.second->second.first).GetFixedPrefDirElementAt(102, ItPair.second->second.second);
16613  EntryLinkPos = PrefDirElement3.ELinkPos;
16614  ExitLinkPos = PrefDirElement3.XLinkPos;
16615  EntryLink = PrefDirElement3.Link[EntryLinkPos];
16616  ExitLink = PrefDirElement3.Link[ExitLinkPos];
16617  if(EntryLink == Track->TrackElementAt(147, TrackVectorPosition).Link[LinkPos])
16618  {
16619  RouteNumber = ItPair.second->second.first;
16620  if(PrefDirElement3.AutoSignals)
16621  {
16622  Utilities->CallLogPop(389);
16623  return AutoSigsRoute;
16624  }
16625  else
16626  {
16627  Utilities->CallLogPop(390);
16628  return NotAutoSigsRoute;
16629  }
16630  }
16631  if(ExitLink == Track->TrackElementAt(148, TrackVectorPosition).Link[LinkPos])
16632  {
16633  RouteNumber = ItPair.second->second.first;
16634  if(PrefDirElement3.AutoSignals)
16635  {
16636  Utilities->CallLogPop(391);
16637  return AutoSigsRoute;
16638  }
16639  else
16640  {
16641  Utilities->CallLogPop(392);
16642  return NotAutoSigsRoute;
16643  }
16644  }
16645  }
16646  RouteNumber = -1;
16647  Utilities->CallLogPop(393);
16648  return NoRoute; // none found
16649 }
16650 
16651 // ---------------------------------------------------------------------------
16652 
16653 void TAllRoutes::StoreOneRoute(int Caller, TOneRoute *Route)
16654 /*
16655  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector, which, since it is the last to be added, will have
16656  a RouteNumber of AllRoutesSize() - 1. Then each element of the new route is added in turn using AddRouteElement,
16657  which uses HLoc, VLoc, ELink and RouteNumber to provide the information necessary to insert it into both PrefDirVector
16658  and Route2MultiMap.
16659 */
16660 {
16661  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRoute");
16662  TOneRoute EmptyRoute;
16663 
16664  EmptyRoute.RouteID = NextRouteID;
16665  NextRouteID++;
16666 
16667  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
16668  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
16669  {
16670  AddRouteElement(0, Route->GetFixedPrefDirElementAt(127, x).HLoc, Route->GetFixedPrefDirElementAt(128, x).VLoc,
16671  Route->GetFixedPrefDirElementAt(129, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(130, x));
16672  }
16673  int FirstVecPos = Route->GetFixedPrefDirElementAt(199, 0).TrackVectorPosition;
16674  int LastVecPos = Route->GetFixedPrefDirElementAt(200, (Route->PrefDirSize()) - 1).TrackVectorPosition;
16675 
16676  TrainController->LogEvent("StoreOneRoute," + AnsiString(EmptyRoute.RouteID) + "," + AnsiString(FirstVecPos) + "," + AnsiString(LastVecPos));
16677  Utilities->CallLogPop(394);
16678 }
16679 
16680 // ---------------------------------------------------------------------------
16681 
16683 /*
16684  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load. For this the RouteID
16685  that is already in Route is used.
16686 */
16687 {
16688  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRouteAfterSessionLoad");
16689  TOneRoute EmptyRoute;
16690 
16691  EmptyRoute.RouteID = Route->RouteID;
16692 
16693  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
16694  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
16695  {
16696  AddRouteElement(3, Route->GetFixedPrefDirElementAt(189, x).HLoc, Route->GetFixedPrefDirElementAt(190, x).VLoc,
16697  Route->GetFixedPrefDirElementAt(191, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(192, x));
16698  }
16699  Utilities->CallLogPop(1579);
16700 }
16701 
16702 // ---------------------------------------------------------------------------
16703 
16704 void TAllRoutes::ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
16705 /*
16706  When attaching a new route section to an existing route, it is sometimes necessary to erase the
16707  original route and create a new composite route. This function Erases all elements in the route
16708  at RouteNumber using TAllRoutes->RemoveRouteElement to clear elements from Route2MultiMap and
16709  from the PrefDirVector. Since all elements for the route are removed RemoveRouteElement also
16710  clears the Route from AllRoutesVector. Route numbers are decremented in the map for route numbers
16711  that are greater than the route number that is removed. The LockedRouteVector as also searched
16712  and if any relate to the route that has been cleared they are erased too, but the fact that one
16713  has been found is recorded so that it can be re-established later.
16714 */
16715 {
16716  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearRouteDuringRouteBuildingAt," + AnsiString(RouteNumber));
16717  THVPair Route2MultiMapKeyPair;
16718  TRoute2MultiMapEntry Route2MultiMapEntry;
16719  TRoute2MultiMapIterator Route2MultiMapIterator;
16720 
16721 // need to check LockedVector first, and erase it if it's the route to be cleared, and to reinstate it as a new locked route with the same
16722 // values (except RouteNumber) when the new route is established (in ConvertAndAdd...).
16723 // If clear all route elements first then when the last is cleared the LockedVector.RouteNumber values are decremented if they are higher
16724 // then the cleared route number (by RemoveRouteElement), and one of the new values may be the same number as the old cleared route number.
16725 // If so the locked route is removed from the locked vector and is lost.
16726  LockedRouteTruncateTrackVectorPosition = 0;
16727  LockedRouteLastTrackVectorPosition = 0;
16728  LockedRouteLastXLinkPos = 0;
16729  LockedRouteLockStartTime = TDateTime(0);
16730  if(!LockedRouteVector.empty())
16731  {
16732  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
16733  {
16734  if(LRVIT->RouteNumber == RouteNumber)
16735  {
16736  LockedRouteTruncateTrackVectorPosition = LRVIT->TruncateTrackVectorPosition;
16737  LockedRouteLastTrackVectorPosition = LRVIT->LastTrackVectorPosition;
16738  LockedRouteLastXLinkPos = LRVIT->LastXLinkPos;
16739  LockedRouteLockStartTime = LRVIT->LockStartTime;
16740  LockedRouteFoundDuringRouteBuilding = true;
16741  LockedRouteVector.erase(LRVIT);
16742  }
16743  }
16744  }
16745 
16746  for(int x = (AllRoutes->GetFixedRouteAt(109, RouteNumber).PrefDirSize()) - 1; x >= 0; x--)
16747  {
16748  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(110, RouteNumber).GetFixedPrefDirElementAt(131, x);
16749  AllRoutes->RemoveRouteElement(7, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.GetELink());
16750  }
16751  Utilities->CallLogPop(395);
16752 }
16753 
16754 // ---------------------------------------------------------------------------
16755 
16757  TRoute2MultiMapIterator &Route2MultiMapIterator)
16758 /*
16759  Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H, V and ELink.
16760  Also returned as a reference is an iterator to the found element in the map to assist in erasing it. Called by
16761  TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink). Note that only need ELink (as well as H & V) to
16762  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different. Messages
16763  are given for failure.
16764 */
16765 {
16766  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRoutePairFromRoute2MultiMap," + AnsiString(HLoc) + "," +
16767  AnsiString(VLoc) + "," + AnsiString(ELink));
16768  TRouteElementPair ReturnPair;
16769 
16770  ReturnPair.first = -1;
16771  ReturnPair.second = 0;
16772  THVPair Route2MultiMapKeyPair;
16773 
16774  Route2MultiMapKeyPair.first = HLoc;
16775  Route2MultiMapKeyPair.second = VLoc;
16776  TRoute2MultiMapEntry Route2MultiMapEntry;
16777 
16778  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
16779  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
16780 
16781  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
16782  Route2MultiMapIterator = ItPair.first;
16783 
16784  if(ItPair.first == ItPair.second)
16785  {
16786  throw Exception("Failed to find Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc);
16787  }
16788 
16789  if(GetFixedRouteAt(111, ItPair.first->second.first).GetFixedPrefDirElementAt(132, ItPair.first->second.second).GetELink() == ELink)
16790  {
16791  ReturnPair.first = ItPair.first->second.first;
16792  ReturnPair.second = ItPair.first->second.second;
16793  Route2MultiMapIterator = ItPair.first;
16794  Utilities->CallLogPop(396);
16795  return ReturnPair;
16796  }
16797  ItPair.first++;
16798  if(ItPair.first == ItPair.second)
16799  {
16800  throw Exception("Found Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc + " but failed to find required element");
16801  }
16802  if(GetFixedRouteAt(112, ItPair.first->second.first).GetFixedPrefDirElementAt(133, ItPair.first->second.second).GetELink() == ELink)
16803  {
16804  ReturnPair.first = ItPair.first->second.first;
16805  ReturnPair.second = ItPair.first->second.second;
16806  Route2MultiMapIterator = ItPair.first;
16807  Utilities->CallLogPop(397);
16808  return ReturnPair;
16809  }
16810  Utilities->CallLogPop(398);
16811  return ReturnPair;
16812 }
16813 
16814 // ---------------------------------------------------------------------------
16815 
16816 bool TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber) // new at v1.2.0
16817 /*
16818  Similar to above but returns a bool and no errors are reported for no route or element at H&V etc.
16819  Examines Route2MultiMap and returns true if oa route is found with the passed values of H, V and ELink.
16820  RouteNumber (route position in AllRoutes vector is returned as a reference.
16821  Called by TTrain::CheckAndCancelRouteForWrongEndEntry. Note that only need ELink (as well as H & V) to
16822  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different.
16823 */
16824 {
16825  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRouteNumberFromRoute2MultiMapNoErrors," + AnsiString(HLoc) + "," +
16826  AnsiString(VLoc) + "," + AnsiString(ELink));
16827  THVPair Route2MultiMapKeyPair;
16828 
16829  Route2MultiMapKeyPair.first = HLoc;
16830  Route2MultiMapKeyPair.second = VLoc;
16831  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
16832 
16833  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
16834 
16835  if(ItPair.first == ItPair.second)
16836  {
16837  RouteNumber = -1;
16838  Utilities->CallLogPop(2032);
16839  return false;
16840  }
16841 
16842  if(GetFixedRouteAt(205, ItPair.first->second.first).GetFixedPrefDirElementAt(241, ItPair.first->second.second).GetELink() == ELink)
16843  {
16844  RouteNumber = ItPair.first->second.first;
16845  Utilities->CallLogPop(2033);
16846  return true;
16847  }
16848 
16849  ItPair.first++;
16850 
16851  if(ItPair.first == ItPair.second)
16852  {
16853  RouteNumber = -1;
16854  Utilities->CallLogPop(2034);
16855  return false;
16856  }
16857 
16858  if(GetFixedRouteAt(206, ItPair.first->second.first).GetFixedPrefDirElementAt(242, ItPair.first->second.second).GetELink() == ELink)
16859  {
16860  RouteNumber = ItPair.first->second.first;
16861  Utilities->CallLogPop(2035);
16862  return true;
16863  }
16864  RouteNumber = -1;
16865  Utilities->CallLogPop(2036);
16866  return false;
16867 }
16868 
16869 // ---------------------------------------------------------------------------
16870 
16871 void TAllRoutes::Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
16872 /*
16873  Elink needed in case it's a bridge, & need to know whether the found element is on this route or not. First check if an
16874  entry in the map already exists at H & V, and if so check that it's a bridge with existing route on other track.
16875  That being so insert the new element. If it's not a bridge, or the route has the same ELink value as the element to
16876  be inserted, give appropriate messages. If there isn't an element at H & V already in the map insert it.
16877  Called by TAllRoutes::AddRouteElement.
16878 */
16879 {
16880  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Route2MultiMapInsert," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
16881  "," + AnsiString(ELinkIn) + "," + AnsiString(RouteNumber) + "," + AnsiString(RouteElementNumber));
16882  THVPair Route2MultiMapKeyPair;
16883 
16884  Route2MultiMapKeyPair.first = HLoc;
16885  Route2MultiMapKeyPair.second = VLoc;
16886  TRoute2MultiMapEntry Route2MultiMapEntry;
16887 
16888  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
16889  TRouteElementPair RouteElementPair;
16890 
16891  RouteElementPair.first = RouteNumber;
16892  RouteElementPair.second = RouteElementNumber;
16893  Route2MultiMapEntry.second = RouteElementPair;
16894 
16895  if(Route2MultiMap.find(Route2MultiMapKeyPair) != Route2MultiMap.end())
16896  // true for element at H&V already included in map, has to be a bridge with existing route on opposite track to be valid
16897  {
16898  if(GetFixedRouteAt(113, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(134,
16899  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).GetELink() != ELinkIn)
16900  // element already at H&V has different ELink to element to be inserted, so must be a bridge with existing route on opposite treack
16901  {
16902  if(GetFixedRouteAt(114, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(135,
16903  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).TrackType != Bridge)
16904  {
16905  throw Exception("Error, bridge expected in Route2MultiMapInsert but not, at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
16906  }
16907  Route2MultiMap.insert(Route2MultiMapEntry); // insert bridge into map again but now with the new track as part of required route
16908  }
16909  else
16910  // same ELink so have an error
16911  {
16912  throw Exception("Error, route map entry found in Route2MultiMapInsert at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
16913  }
16914  }
16915  else
16916  Route2MultiMap.insert(Route2MultiMapEntry);
16917 // element at H&V not found in map so insert it
16918  Utilities->CallLogPop(399);
16919 }
16920 
16921 // ---------------------------------------------------------------------------
16922 
16924 /*
16925  Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function return
16926  and the second in the reference SecondPair. If there's only one then it's the function return
16927 */
16928 {
16929  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteElementDataFromRoute2MultiMap," + AnsiString(HLoc) + "," +
16930  AnsiString(VLoc));
16932 
16933  TempPair.first = -1;
16934  TempPair.second = 0;
16935  SecondPair = TempPair;
16936  TRoute2MultiMapIterator Route2MultiMapIterator;
16937  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItRange;
16938  THVPair Route2MultiMapKeyPair;
16939 
16940  Route2MultiMapKeyPair.first = HLoc;
16941  Route2MultiMapKeyPair.second = VLoc;
16942  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
16943  {
16944  Utilities->CallLogPop(400);
16945  return TempPair;
16946  }
16947  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
16948  {
16949  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
16950  Utilities->CallLogPop(401);
16951  return Route2MultiMapIterator->second;
16952  }
16953  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
16954  {
16955  ItRange = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
16956  TempPair = ItRange.first->second;
16957  SecondPair = (--ItRange.second)->second; // 2nd iterator points past the last value
16958  Utilities->CallLogPop(402);
16959  return TempPair;
16960  }
16961  Utilities->CallLogPop(403);
16962  return TempPair;
16963 }
16964 
16965 // ---------------------------------------------------------------------------
16966 
16967 void TAllRoutes::CheckMapAndRoutes(int Caller) // test
16968 /*
16969  Checks equivalence for each route between entries in PrefDirVector and those in Route2MultiMap, and also that the size
16970  of the multimap and the sum of the sizes of all PrefDirVectors is the same.
16971 */
16972 {
16973  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndRoutes");
16974  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
16975  {
16976  for(unsigned int b = 0; b < AllRoutes->GetFixedRouteAt(115, a).PrefDirSize(); b++)
16977  {
16978  TPrefDirElement CheckElement = AllRoutes->GetFixedRouteAt(116, a).GetFixedPrefDirElementAt(136, b);
16979  TAllRoutes::TRouteElementPair SecondPair;
16980  TRouteElementPair RouteElementPair = GetRouteElementDataFromRoute2MultiMap(8, CheckElement.HLoc, CheckElement.VLoc, SecondPair);
16981  if(RouteElementPair.first == -1)
16982  // failed to find element in multimap
16983  {
16984  throw Exception("CheckMapAndRoutes Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
16985  " in Route2MultiMap, Caller=" + (AnsiString)Caller);
16986  }
16987  if((RouteElementPair.first != (int)a) && (SecondPair.first != (int)a))
16988  // neither pair has expected route number
16989  {
16990  throw Exception("CheckMapAndRoutes Error - RouteNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
16991  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)RouteElementPair.first + " Route value=" + (AnsiString)a + " Caller=" +
16992  (AnsiString)Caller);
16993  }
16994  if(((RouteElementPair.first != (int)a) || (RouteElementPair.second != b)) && ((SecondPair.first != (int)a) || (SecondPair.second != b)))
16995  // need one of pairs to match both RouteNumber and RouteElementNumber or fails
16996  {
16997  throw Exception("CheckMapAndRoutes Error - PrefDirVectorNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
16998  (AnsiString)CheckElement.VLoc + " 1st Map value RouteNum/ElementNum =" + (AnsiString)RouteElementPair.first + "/" +
16999  (AnsiString)RouteElementPair.second + " 2nd Map value =" + (AnsiString)SecondPair.first + "/" + (AnsiString)SecondPair.second +
17000  " Route value=" + (AnsiString)a + "/" + (AnsiString)b + " Caller=" + (AnsiString)Caller);
17001  }
17002  }
17003  }
17004  unsigned int SizeVal = 0;
17005 
17006 // check map and sum of route sizes match
17007  for(unsigned int a = 0; a < AllRoutesSize(); a++)
17008  {
17009  SizeVal += GetFixedRouteAt(117, a).PrefDirSize();
17010  }
17011  if(SizeVal != Route2MultiMap.size())
17012  {
17013  throw Exception("CheckMapAndRoutes Error - Map Size=" + (AnsiString)Route2MultiMap.size() + " RouteSize=" + (AnsiString)SizeVal + " Caller=" +
17014  (AnsiString)Caller);
17015  }
17016  Utilities->CallLogPop(404);
17017  return;
17018 }
17019 
17020 // ---------------------------------------------------------------------------
17021 
17022 void TAllRoutes::DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
17023 /*
17024  After a route has been erased from AllRoutesVector and its entries from Route2MultiMap, this
17025  function examines all the remaining entries in Route2MultiMap to see if their RouteNumbers
17026  exceed that for the erased route. Where this is so the RouteNumber is decremented.
17027 */
17028 {
17029  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteNumbersInRoute2MultiMap," + AnsiString(RouteNumber));
17030  if(!Route2MultiMap.empty())
17031  {
17032  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
17033  {
17034  if(Route2MultiMapIterator->second.first > RouteNumber)
17035  Route2MultiMapIterator->second.first--;
17036  }
17037  }
17038  Utilities->CallLogPop(405);
17039 }
17040 
17041 // ---------------------------------------------------------------------------
17042 
17043 void TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
17044 /*
17045  After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap, this
17046  function examines all the remaining entries in Route2MultiMap with the same RouteNumber as that
17047  for the erased element. Where a RouteElementNumber exceeds that for the erased element it is decremented.
17048 */
17049 {
17050  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteElementNumbersInRoute2MultiMap," +
17051  AnsiString(RouteNumber) + "," + AnsiString(ErasedElementNumber));
17052  if(!Route2MultiMap.empty())
17053  {
17054  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
17055  {
17056  if((Route2MultiMapIterator->second.first == RouteNumber) && (Route2MultiMapIterator->second.second > ErasedElementNumber))
17057  Route2MultiMapIterator->second.second--;
17058  }
17059  }
17060  Utilities->CallLogPop(406);
17061 }
17062 
17063 // ---------------------------------------------------------------------------
17064 
17065 void TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
17066 /*
17067  Erases the route element from Route2MultiMap and from the PrefDirVector.
17068  If there are no elements left in the PrefDirVector the route is cleared from AllRoutesVector. Route element numbers in the map are
17069  decremented if they are greater than the element number removed, and if the entire route is removed
17070  then the route numbers are also decremented in the map for route numbers that are greater than the route
17071  number that is removed.
17072 */
17073 {
17074  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RemoveRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
17075  AnsiString(ELink));
17076  TRouteElementPair RequiredRoutePair; // RouteNumber & RouteElementNumber
17077  TRoute2MultiMapIterator Route2MultiMapIterator;
17078 
17079  RequiredRoutePair = FindRoutePairFromRoute2MultiMap(0, HLoc, VLoc, ELink, Route2MultiMapIterator);
17080  if(RequiredRoutePair.first == -1)
17081  {
17082  throw Exception("Failed to find route element in RemoveRouteElement");
17083  }
17084  Route2MultiMap.erase(Route2MultiMapIterator);
17085  DecrementRouteElementNumbersInRoute2MultiMap(0, RequiredRoutePair.first, RequiredRoutePair.second);
17086 
17087 // even though element has been erased from the routemap, RequiredRoutePair still contains the element values
17088  TPrefDirElement LockedRouteElement, PrefDirElement = GetFixedRouteAt(118, RequiredRoutePair.first).GetFixedPrefDirElementAt(137, RequiredRoutePair.second);
17089 
17090  if(Track->TrackElementAt(157, PrefDirElement.TrackVectorPosition).Config[PrefDirElement.XLinkPos] == Signal)
17091  {
17092  Track->TrackElementAt(158, PrefDirElement.TrackVectorPosition).Attribute = 0; // change forward signals back to red
17093  }
17094 
17095 // don't need the section below (a) because when a train removes elements from the front of a locked route, there is a test in
17096 // ApproachLocking to determine whether the element immediately nearer the start of the route to the element being removed is still
17097 // present, and of not the element removal stops; and (b) because it never worked anyway! - IsElementInLockedRoute.... uses Route2MultiMap
17098 // to check if a route element is present, and the element has already been removed from the map - see above.
17099 
17100 // before erase the element check if it's in a locked route, and if so change the TruncateTrackVectorPosition to the next valid (XLinkPos] element position
17101 /*
17102  int LockedVectorNumber = -1;
17103  if(IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(5, PrefDirElement.TrackVectorPosition, PrefDirElement.XLinkPos, LockedRouteElement, LockedVectorNumber))
17104  {
17105  LockedRouteVector.at(LockedVectorNumber).TruncateTrackVectorPosition = PrefDirElement.Conn[PrefDirElement.XLinkPos];
17106  }
17107 */
17108 
17109 // erase element from route
17110  GetModifiableRouteAt(8, RequiredRoutePair.first).EraseRouteElementAt(&(GetModifiableRouteAt(9, RequiredRoutePair.first).GetModifiablePrefDirElementAt(1,
17111  RequiredRoutePair.second)));
17112 // CheckMapAndRoutes();//test - drop - tested below
17113 
17114 // remove ContinuationAutoSig route if element is in one since if any part of it is truncated the continuation exit will be removed - must
17115 // be so as continuation exit is at the end of the route, and truncation is from the end
17117  {
17119  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
17120  AutoSigVectorIT--)
17121  {
17122  if(AutoSigVectorIT->RouteNumber == RequiredRoutePair.first)
17123  {
17124  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT);
17125  }
17126  }
17127  }
17128 
17129 // now if last element from a route was removed need to remove the route from the route vector and from the LockedRouteVector if exists,
17130 // and adjust all the corresponding route numbers
17131  if(GetModifiableRouteAt(10, RequiredRoutePair.first).PrefDirSize() == 0)
17132  {
17133  TrainController->LogEvent("RouteRemoved," + AnsiString(GetFixedRouteAt(189, RequiredRoutePair.first).RouteID));
17134  AllRoutesVector.erase(AllRoutesVector.begin() + RequiredRoutePair.first);
17135  DecrementRouteNumbersInRoute2MultiMap(0, RequiredRoutePair.first);
17136 
17137 /* drop this: LockedVectorNumber was supposed to be determined from the above section that has been dropped, so this doesn't work
17138  It isn't needed anyway as a check is made after the Locked route timeout as to whether the end element is in a route or not, and if not
17139  it is erased then - see TInterface::ApproachLocking
17140 
17141  if(LockedVectorNumber > -1)
17142  {
17143  LockedRouteVector.erase(LockedRouteVector.begin() + LockedVectorNumber);
17144  }
17145 */
17146  // decrement route numbers in the locked route vector whether or not this route is a locked route
17147  if(!LockedRouteVector.empty())
17148  {
17149  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
17150  {
17151  if(LRVIT->RouteNumber > RequiredRoutePair.first)
17152  {
17153  LRVIT->RouteNumber--;
17154  }
17155  }
17156  }
17157 
17159  {
17161  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
17162  AutoSigVectorIT--)
17163  {
17164  if(AutoSigVectorIT->RouteNumber > RequiredRoutePair.first)
17165  AutoSigVectorIT->RouteNumber--;
17166  }
17167  }
17168  }
17169  CheckMapAndRoutes(7); // test
17170  Utilities->CallLogPop(407);
17171 }
17172 
17173 // ---------------------------------------------------------------------------
17174 
17175 void TAllRoutes::AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
17176 /*
17177  A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2MultiMap.
17178  Called from TAllRoutes::StoreOneRoute. Note that the IsARoute boolean variable is set in StoreRouteElementInPrefDirVector
17179  since that catches all route elements wherever created
17180 */
17181 {
17182  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
17183  AnsiString(ELink) + "," + AnsiString(RouteNumber) + "," + RouteElement.LogPrefDir());
17184  GetModifiableRouteAt(11, RouteNumber).StoreRouteElementInPrefDirVector(RouteElement);
17185  Route2MultiMapInsert(0, HLoc, VLoc, ELink, RouteNumber, GetModifiableRouteAt(12, RouteNumber).PrefDirSize() - 1);
17186  Utilities->CallLogPop(408);
17187 }
17188 
17189 // ---------------------------------------------------------------------------
17190 
17191 void TAllRoutes::SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
17192 /*
17193  Enter with signal at TrackVectorElement already set to red by the passing train.
17194  Identify the route that the TrackVectorPosition is in, carry out validity checks, then call SetAllRearwardsSignals to set signals
17195  in this route and all linked rearwards routes, unless find a train (a) in the current route, in which case the signals behind it are
17196  set (and behind any other trains in the current route), but only within the current route; or (b) in a linked rear route, in which
17197  case the function sets no further signals.
17198 */
17199 {
17200  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnAutoSigsRoute," + AnsiString(TrackVectorPosition) +
17201  "," + AnsiString(XLinkPos));
17202  TRouteElementPair RouteElementPair, SecondPair, RequiredPair;
17203  TTrackElement TE = Track->TrackElementAt(159, TrackVectorPosition);
17204 
17205  RouteElementPair = GetRouteElementDataFromRoute2MultiMap(9, TE.HLoc, TE.VLoc, SecondPair);
17206  if(RouteElementPair.first == -1)
17207  {
17208  throw Exception("Error, failed to find element in SetTrailingSignalsOnAutoSigsRoute - 1");
17209  }
17210  TPrefDirElement RouteElement = GetFixedRouteAt(119, RouteElementPair.first).GetFixedPrefDirElementAt(138, RouteElementPair.second);
17211 
17212  RequiredPair = RouteElementPair;
17213  if(RouteElement.XLinkPos != XLinkPos)
17214  {
17215  if(SecondPair.first != -1)
17216  {
17217  RouteElement = GetFixedRouteAt(120, SecondPair.first).GetFixedPrefDirElementAt(139, SecondPair.second);
17218  RequiredPair = SecondPair;
17219  if(RouteElement.XLinkPos != XLinkPos)
17220  {
17221  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 2");
17222  }
17223  }
17224  else
17225  {
17226  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 3");
17227  }
17228  }
17229 
17230 // new function
17231  SetAllRearwardsSignals(5, 0, RequiredPair.first, RequiredPair.second);
17232  Utilities->CallLogPop(409);
17233 }
17234 
17235 // ---------------------------------------------------------------------------
17236 
17237 void TAllRoutes::SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
17238 /*
17239  This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in TrainController to set signals on
17240  the AutoSigsRoute to correspond to a train having exited the route at a continuation, and passing further signals (outside the simulated
17241  railway). Initially the last passed signal will be red, then at the first call it will change to yellow and earlier signals will change
17242  accordingly, then double yellow, then green. There are only 3 calls in all for any given route, and the AccessNumber changes from 0 to 1
17243  to 2 for successive calls.
17244  Initially Attribute is set to AccessNumber + 1 to correspond to the first signal attribute to be set, then a number of validity checks
17245  are carried out on RouteNumber. Then SetAllRearwardsSignals is called to set signals in this route and all linked rearwards routes,
17246  unless find a train (a) in the current route, in which case the signals behind it are set (and behind any other trains in the current
17247  route), but only within the current route; or (b) in a linked rear route, in which case the function sets no further signals.
17248 */
17249 {
17250  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnContinuationRoute," + AnsiString(RouteNumber) + "," +
17251  AnsiString(AccessNumber));
17252  TPrefDirElement RouteElement;
17253  int Attribute = AccessNumber + 1;
17254 // signal attributes: 0=red; 1=yellow; 2=double yellow; 3 = green
17255  int x = GetFixedRouteAt(121, RouteNumber).PrefDirSize() - 1;
17256 
17257  if(!(GetFixedRouteAt(122, RouteNumber).GetFixedPrefDirElementAt(140, x).AutoSignals))
17258  {
17259  throw Exception("Error - route not AutoSignals in SetTrailingSignalsOnContinuationRoute");
17260  }
17261  if(GetFixedRouteAt(123, RouteNumber).GetFixedPrefDirElementAt(141, x).TrackType != Continuation)
17262  {
17263  throw Exception("Error - end element not continuation in SetTrailingSignalsOnContinuationRoute");
17264  }
17265  if(GetFixedRouteAt(124, RouteNumber).GetFixedPrefDirElementAt(142, x).Config[GetFixedRouteAt(125, RouteNumber).GetFixedPrefDirElementAt(143,
17266  x).XLinkPos] != End)
17267  {
17268  throw Exception("Error - end element a continuation in SetTrailingSignalsOnContinuationRoute but End not facing right way");
17269  }
17270 // new function
17271  SetAllRearwardsSignals(6, Attribute, RouteNumber, GetFixedRouteAt(126, RouteNumber).PrefDirSize() - 1);
17272  Utilities->CallLogPop(410);
17273 }
17274 
17275 // ---------------------------------------------------------------------------
17276 
17277 void TAllRoutes::SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
17278 /*
17279  Sets signals in all linked rearwards routes from the RouteStartPosition in RouteNumber, unless find a train (a) in the current route,
17280  in which case the signals behind it are set (and behind any other trains in the current route), but only within the current route;
17281  or (b) in a linked rear route, in which case the function sets no further signals.
17282 
17283  First call SetRearwardsSignalsReturnFalseForTrain (which is only called by this function) to set signals in route RouteNumber according
17284  to the received or modified (because of the forward look for buffers or continuation) Attribute. If no train is found during this call
17285  (returns true) then check for and call SetRearwardsSignalsReturnFalseForTrain for each rearwards linked route until either reach the
17286  beginning of the last linked route or find a train on a linked rear route. If no train was found during the RouteNumber call to
17287  SetRearwardsSignalsReturnFalseForTrain then the function terminates here.
17288  However if a train was found during the RouteNumber call to SetRearwardsSignalsReturnFalseForTrain then need to continue after the
17289  train in case had just added a route segment behind a train that now forms part of a single continuous route, otherwise the signals
17290  won't be set behind the train. First the route is examined element by element from the RouteStartPosition towards the start of the
17291  route until the train is found. Then the route elements are examined from the TrainPosition towards the start of the route until the
17292  first element behind the train is found. A recursive call to this function is then made from this behind-train position, to set all
17293  signals behind the train (and behind as many trains as there are on the single route) beginning with a red signal for the first signal
17294  found behind the train.
17295 
17296  Description of SetRearwardsSignalsReturnFalseForTrain for reference:
17297  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
17298  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
17299  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
17300  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
17301  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
17302  a route.
17303 
17304  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
17305  signal. If find a signal set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
17306  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3 and continue working backwards
17307  for the next signal (or train - return false as before) and so on. On completion Attribute is passed back from the function as a
17308  reference. If no train is found before the beginning of the route is reached the function returns true.
17309 
17310 */
17311 {
17312  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllRearwardsSignals," + AnsiString(Attribute) + "," +
17313  AnsiString(RouteNumber) + "," + AnsiString(RouteStartPosition));
17314  TPrefDirElement FirstElement = GetFixedRouteAt(127, RouteNumber).GetFixedPrefDirElementAt(144, 0);
17315  int RearwardLinkedRouteNumber;
17316 
17317  Track->LCFoundInRouteBuildingFlag = false; // only examined for the new route segment, not for linked routes
17318  if(GetFixedRouteAt(128, RouteNumber).SetRearwardsSignalsReturnFalseForTrain(1, Attribute, RouteStartPosition)) // updates Attribute to 1+ final
17319  // signal value in the route for use in further linked routes
17320  {
17321  if(FirstElement.Conn[FirstElement.ELinkPos] > -1) // GetRouteTypeAndNumber tests for this but check here to avoid call if == -1
17322  {
17323  while(GetRouteTypeAndNumber(6, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
17324  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
17325  {
17326  if(!(GetFixedRouteAt(129, RearwardLinkedRouteNumber).SetRearwardsSignalsReturnFalseForTrain(2, Attribute, AllRoutes->GetFixedRouteAt(130,
17327  RearwardLinkedRouteNumber).PrefDirSize() - 1)))
17328  break;
17329  // in above the RouteSettingFlag is set to false because this call is for routes that lie behind the route that is being set so don't want to
17330  // flash LCs on those routes
17331  FirstElement = AllRoutes->GetFixedRouteAt(131, RearwardLinkedRouteNumber).GetFixedPrefDirElementAt(145, 0);
17332  }
17333  }
17334  }
17335  else
17336  // found a train in the entry route before the beginning of the route, so need to continue after the train in case had just added a
17337  // route segment behind a train that now forms part of a single continuous route, otherwise the signals won't be set behind the train
17338  {
17339  int TrainID, TrainPosition, BehindTrainPosition;
17340  bool FoundTrain = false, BehindTrain = false;
17341  for(int x = RouteStartPosition; x >= 0; x--) // first step back from start position until find the train....
17342  {
17343  TPrefDirElement PrefDirElement = GetFixedRouteAt(132, RouteNumber).GetFixedPrefDirElementAt(146, x);
17344  TTrackElement TrackElement = Track->TrackElementAt(160, PrefDirElement.TrackVectorPosition);
17345  TrainID = TrackElement.TrainIDOnElement;
17346  if(TrackElement.TrackType == Bridge)
17347  {
17348  if(PrefDirElement.XLinkPos < 2)
17349  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
17350  else
17351  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
17352  }
17353  if(TrainID == -1)
17354  continue;
17355  else
17356  {
17357  FoundTrain = true;
17358  TrainPosition = x;
17359  break;
17360  }
17361  }
17362  if(FoundTrain && (TrainPosition > 1)) // if TrainPosition 1 or less then no route behind the train so can stop
17363  {
17364  for(int x = TrainPosition; x >= 0; x--) // then step back from that position until find element behind the train - ignore any
17365  // signals that the train itself is straddling, need the first signal behind the train to be set to red, when the train passes
17366  // the signal it's straddling the rearwards signals will be reset again. Even if there are two or more trains adjacent still
17367  // need the element behind the rearmost train.
17368  {
17369  TPrefDirElement PrefDirElement = GetFixedRouteAt(133, RouteNumber).GetFixedPrefDirElementAt(147, x);
17370  TTrackElement TrackElement = Track->TrackElementAt(161, PrefDirElement.TrackVectorPosition);
17371  TrainID = TrackElement.TrainIDOnElement;
17372  if(TrackElement.TrackType == Bridge)
17373  {
17374  if(PrefDirElement.XLinkPos < 2)
17375  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
17376  else
17377  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
17378  }
17379  if(TrainID != -1)
17380  continue; // still on train
17381  else
17382  {
17383  BehindTrain = true;
17384  BehindTrainPosition = x;
17385  break;
17386  }
17387  }
17388  if(BehindTrain) // then carry out a recursive rearward signal setting behind the train &
17389  // so on for as many trains as there are on the single route
17390  {
17391  SetAllRearwardsSignals(7, 0, RouteNumber, BehindTrainPosition); // false because can't set a route where there is a train
17392  // first signal behind train to be red
17393  }
17394  }
17395  }
17396  Utilities->CallLogPop(411);
17397 }
17398 
17399 // ---------------------------------------------------------------------------
17400 
17401 bool TAllRoutes::RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
17402 {
17403 /* Locked if a train moving in the direction of the route within 3 signals back from truncate point (on the route itself or any linked routes, or on the element
17404  immediately before the start of the route or linked route - this because train cancels route elements that it touches) unless
17405  first signal is red, then OK
17406 */
17407  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteLockingRequired," + AnsiString(RouteNumber) + "," +
17408  AnsiString(RouteTruncatePosition));
17409  int SignalCount = 0, TrainID, RearwardLinkedRouteNumber, StartPosition = RouteTruncatePosition;
17410  TOneRoute CurrentRoute = GetFixedRouteAt(134, RouteNumber);
17411  TPrefDirElement PrefDirElement, FirstElement;
17412  TTrackElement TrackElement;
17413  bool ExamineRoute = true;
17414 
17415  while(ExamineRoute)
17416  {
17417  for(int x = StartPosition; x >= 0; x--) //work back along the route from the truncate point
17418  {
17419  PrefDirElement = CurrentRoute.GetFixedPrefDirElementAt(148, x);
17420  TrackElement = Track->TrackElementAt(162, PrefDirElement.TrackVectorPosition);
17421  TrainID = TrackElement.TrainIDOnElement;
17422  if(TrackElement.TrackType == Bridge)
17423  {
17424  if(PrefDirElement.XLinkPos < 2)
17425  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
17426  else
17427  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
17428  }
17429  if(TrainID > -1)
17430  {
17431  if(TrainController->TrainVectorAtIdent(36, TrainID).Stopped())
17432  { //any trains further back in route will be protected by the red signal behind the stopped train
17433  Utilities->CallLogPop(412);
17434  return false;
17435  }
17436  //added after v2.4.1 for trains facing the wrong way & moving but haven't moved a half element yet so route still intact
17437  if(TrainController->TrainVectorAtIdent(49, TrainID).GetLeadElement() != PrefDirElement.TrackVectorPosition) //if it isn't then the train is facing the
17438  //other way & can cancel the route
17439  {
17440  Utilities->CallLogPop(2203);
17441  return false;
17442  }
17443  Utilities->CallLogPop(1961); //otherwise need to lock the route as have found a train on the route (trains forward of the truncate point caught by
17444  return true; //TrainOccupyingRoute which is outside this function but also causes route locking)
17445  }
17446  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal) // XLinkPos because signal has to be facing same direction as PrefDir to count
17447  {
17448  if(TrackElement.Attribute == 0)
17449  {
17450  Utilities->CallLogPop(413);
17451  return false; // OK, red signal in front of a train
17452  }
17453  SignalCount++;
17454  if(SignalCount >= 3)
17455  {
17456  Utilities->CallLogPop(414);
17457  return false;
17458  }
17459  }
17460  if(PrefDirElement.Config[PrefDirElement.ELinkPos] == End) // buffer or continuation & no train
17461  // ElinkPos because working back along PrefDir to beginning
17462  {
17463  Utilities->CallLogPop(415);
17464  return false; // test - set to true to create a locked buffer-ended route, false for normal use
17465  }
17466  }
17467  //now look at linked rearwards routes
17468  FirstElement = CurrentRoute.GetFixedPrefDirElementAt(149, 0);
17469  StartPosition = CurrentRoute.PrefDirSize() - 1;
17470  if(GetRouteTypeAndNumber(7, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
17471  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
17472  {
17473  CurrentRoute = GetFixedRouteAt(135, RearwardLinkedRouteNumber);
17474  ExamineRoute = true;
17475  StartPosition = GetFixedRouteAt(136, RearwardLinkedRouteNumber).PrefDirSize() - 1;
17476  }
17477  else
17478  {
17479  // here check for a train on the element immediately before the first route element
17480  TTrackElement PriorTrackElement = Track->TrackElementAt(489, FirstElement.Conn[FirstElement.ELinkPos]);
17481  TrainID = PriorTrackElement.TrainIDOnElement;
17482  if(PriorTrackElement.TrackType == Bridge)
17483  {
17484  if(FirstElement.ConnLinkPos[FirstElement.ELinkPos] < 2)
17485  TrainID = PriorTrackElement.TrainIDOnBridgeTrackPos01;
17486  else
17487  TrainID = PriorTrackElement.TrainIDOnBridgeTrackPos23;
17488  }
17489  if(TrainID > -1)
17490  {
17491  if(TrainController->TrainVectorAtIdent(37, TrainID).Stopped())
17492  {
17493  Utilities->CallLogPop(748);
17494  return false;
17495  }
17496  //added after v2.4.1 for trains facing the wrong way on the prior element & moving but haven't moved a half element yet
17497  if(TrainController->TrainVectorAtIdent(50, TrainID).GetLeadElement() != FirstElement.Conn[FirstElement.ELinkPos]) //if it isn't then the train is facing the
17498  //other way & can cancel the route
17499  {
17500  Utilities->CallLogPop(2204);
17501  return false;
17502  }
17503  Utilities->CallLogPop(1962);
17504  return true; //otherwise need to lock the route
17505  }
17506  ExamineRoute = false;
17507  }
17508  }
17509 // if reach beginning of all rear routes without finding a train and there aren't 3 signals then truncate the route
17510 // as trains running on unrouted lines are already at risk of wrong points etc so no benefit locking the route
17511  Utilities->CallLogPop(416);
17512  return false;
17513 }
17514 
17515 // ---------------------------------------------------------------------------
17516 
17517 bool TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos,
17518  TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
17519 {
17520  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber," +
17521  AnsiString(TrackVectorPosition) + "," + AnsiString(XLinkPos));
17522  TPrefDirElement InternalPrefDirElement; // blank element
17523 
17524  PrefDirElement = InternalPrefDirElement;
17525  if(LockedRouteVector.empty())
17526  {
17527  Utilities->CallLogPop(417);
17528  return false;
17529  }
17530 // make sure at least one locked route record is still valid - train may have removed it, if last element still present locked route still exists,
17531 // even if some elements have been removed from the front by a train
17532  bool InLockedRoute = false;
17533 
17534  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
17535  {
17536  if(TrackIsInARoute(14, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
17537  { // end of route can't be points, crossover or bridge so danger of route being on the other track of a 2-track element
17538  // doesn't arise)
17539  InLockedRoute = true;
17540  break;
17541  }
17542  }
17543  if(!InLockedRoute)
17544  {
17545  Utilities->CallLogPop(418);
17546  return false;
17547  }
17548 
17549  int RouteNumber, VectorCount = 0;
17550  TRouteType RouteType;
17551 
17552  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
17553  {
17554  RouteType = GetRouteTypeAndNumber(8, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos, RouteNumber);
17555  if(RouteType == NoRoute)
17556  continue;
17557  if((GetFixedRouteAt(137, RouteNumber).GetFixedPrefDirElementAt(150, GetFixedRouteAt(138, RouteNumber).PrefDirSize() - 1).TrackVectorPosition != (int)
17558  LRVIT->LastTrackVectorPosition) || (GetFixedRouteAt(139, RouteNumber).GetFixedPrefDirElementAt(151,
17559  GetFixedRouteAt(140, RouteNumber).PrefDirSize() - 1).XLinkPos != LRVIT->LastXLinkPos))
17560  {
17561  throw Exception
17562  ("Error, last element in locked route doesn't correspond with last element in associated route in IsElementInLockedRouteGetPrefDirElement");
17563  }
17564  for(int x = GetFixedRouteAt(141, RouteNumber).PrefDirSize() - 1; x >= 0; x--)
17565  {
17566  InternalPrefDirElement = GetFixedRouteAt(142, RouteNumber).GetFixedPrefDirElementAt(152, x);
17567  if(InternalPrefDirElement.TrackVectorPosition != (int)LRVIT->TruncateTrackVectorPosition)
17568  {
17569  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
17570  {
17571  PrefDirElement = InternalPrefDirElement;
17572  LockedVectorNumber = VectorCount;
17573  Utilities->CallLogPop(419);
17574  return true;
17575  }
17576  }
17577  else if(InternalPrefDirElement.TrackVectorPosition == (int)LRVIT->TruncateTrackVectorPosition)
17578  {
17579  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
17580  {
17581  PrefDirElement = InternalPrefDirElement;
17582  LockedVectorNumber = VectorCount;
17583  Utilities->CallLogPop(420);
17584  return true;
17585  }
17586  else
17587  break; // reached & tested LRVIT->TruncateTrackVectorPosition for a match so don't want to go any further for this route
17588  }
17589  }
17590  VectorCount++;
17591  }
17592  Utilities->CallLogPop(421);
17593  return false;
17594 }
17595 
17596 // ---------------------------------------------------------------------------
17597 
17599 {
17600  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteVectorNumber," + AnsiString(RouteID.GetInt()));
17601  for(unsigned int x = 0; x < AllRoutesSize(); x++)
17602  {
17603  if(GetFixedRouteAt(157, x).RouteID == RouteID.GetInt())
17604  {
17605  Utilities->CallLogPop(963);
17606  return x;
17607  }
17608  }
17609  throw Exception("Error, failed to find RouteID in GetRouteVectorNumber for ID: " + AnsiString(RouteID.GetInt()));
17610 }
17611 
17612 // ---------------------------------------------------------------------------
17613 
17615  // added at v1.3.1 after an error was generated when operating Ian Walker's Chiltern Railway
17616  // found to be due to a route having been removed by a train moving in the wrong direction after the route was selected but before it completed (i.e. route removed while flashing)
17617 {
17618  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsThereARouteAtIDNumber," + AnsiString(RouteID.GetInt()));
17619  for(unsigned int x = 0; x < AllRoutesSize(); x++)
17620  {
17621  if(GetFixedRouteAt(45, x).RouteID == RouteID.GetInt())
17622  {
17623  Utilities->CallLogPop(2039);
17624  return true;
17625  }
17626  }
17627  Utilities->CallLogPop(2040);
17628  return false;
17629 }
17630 
17631 // ---------------------------------------------------------------------------
17632 
17634 {
17635  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAtIDNumber," + AnsiString(RouteID.GetInt()));
17636  for(unsigned int x = 0; x < AllRoutesSize(); x++)
17637  {
17638  if(GetFixedRouteAt(163, x).RouteID == RouteID.GetInt())
17639  {
17640  Utilities->CallLogPop(964);
17641  return GetFixedRouteAt(159, x);
17642  }
17643  }
17644  throw Exception("Error, failed to find RouteID in GetFixedRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
17645 }
17646 
17647 // ---------------------------------------------------------------------------
17648 
17650 {
17651  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteATIDNumber," + AnsiString(RouteID.GetInt()));
17652  for(unsigned int x = 0; x < AllRoutesSize(); x++)
17653  {
17654  if(GetFixedRouteAt(164, x).RouteID == RouteID.GetInt())
17655  {
17656  Utilities->CallLogPop(965);
17657  return GetModifiableRouteAt(15, x);
17658  }
17659  }
17660  throw Exception("Error, failed to find RouteID in GetModifiableRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
17661 }
17662 
17663 // ---------------------------------------------------------------------------
17664 
17665 void TAllRoutes::SaveRoutes(int Caller, std::ofstream &OutFile)
17666 {
17667  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveRoutes");
17668  Utilities->SaveFileInt(OutFile, AllRoutesSize()); // so know how many to reload
17669  Utilities->SaveFileInt(OutFile, NextRouteID);
17670  for(unsigned int x = 0; x < AllRoutesSize(); x++)
17671  {
17672  TOneRoute OneRoute = GetFixedRouteAt(165, x);
17673  Utilities->SaveFileInt(OutFile, OneRoute.RouteID);
17674  OneRoute.SavePrefDirVector(6, OutFile);
17675  }
17676  Utilities->CallLogPop(1442);
17677 }
17678 
17679 // ---------------------------------------------------------------------------
17680 
17681 bool TAllRoutes::LoadRoutes(int Caller, std::ifstream &InFile)
17682 {
17683  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRoutes");
17684  int NumberOfRoutes;
17685 
17686  NumberOfRoutes = Utilities->LoadFileInt(InFile);
17687  NextRouteID = Utilities->LoadFileInt(InFile);
17688  for(int x = 0; x < NumberOfRoutes; x++)
17689  {
17690  TOneRoute OneRoute; // empty route
17691  OneRoute.RouteID = Utilities->LoadFileInt(InFile);
17692  OneRoute.LoadPrefDir(2, InFile);
17694  {
17695  StoreOneRouteAfterSessionLoad(0, &OneRoute);
17696  }
17697  else
17698  {
17699  Utilities->CallLogPop(1443);
17700  return false;
17701  }
17702  }
17703  Utilities->CallLogPop(1444);
17704  return true;
17705 }
17706 
17707 // ---------------------------------------------------------------------------
17708 bool TAllRoutes::CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
17709 {
17710  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckRoutes," + AnsiString(NumberOfActiveElements));
17711  int NumberOfRoutes = Utilities->LoadFileInt(InFile);
17712 
17713  if((NumberOfRoutes < 0) || (NumberOfRoutes > 5000))
17714  {
17715  Utilities->CallLogPop(1445);
17716  return false;
17717  }
17718  int NextID = Utilities->LoadFileInt(InFile);
17719 
17720  if((NextID < 0) || (NextID > 1000000))
17721  {
17722  Utilities->CallLogPop(1446);
17723  return false;
17724  }
17725  for(int x = 0; x < NumberOfRoutes; x++)
17726  {
17727  int RouteID = Utilities->LoadFileInt(InFile);
17728  if((RouteID < 0) || (RouteID > 20000))
17729  {
17730  Utilities->CallLogPop(1447);
17731  return false;
17732  }
17733  TOneRoute OneRoute; // create an empty route so CheckOnePrefDir can be called
17734  if(!(OneRoute.CheckOnePrefDir(3, NumberOfActiveElements, InFile)))
17735  {
17736  Utilities->CallLogPop(1448);
17737  return false;
17738  }
17739  }
17740  Utilities->CallLogPop(1449);
17741  return true;
17742 }
17743 
17744 // ---------------------------------------------------------------------------
17745 
17746 bool TAllRoutes::CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
17747 { // return true for a loop
17748  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckForLoopingRoute," + AnsiString(EndPosition) + "," +
17749  AnsiString(StartPosition));
17750  if(EndPosition == StartPosition)
17751  {
17752  Utilities->CallLogPop(1839);
17753  return true; // shouldn't happen but treat as a loop if does
17754  }
17755 // begin at EndPosition & EndXLinkPos & work forwards until reach end of route (return false) or StartElement (return true)
17756  int TVPos = EndPosition; //TVPos is the current element and NewTVPos is the element it connects to
17757  int LkPos = EndXLinkPos; //LkPos is the exit link and NewLkPos is the entry link of the linked element
17758 
17759  while(TrackIsInARoute(15, TVPos, LkPos))
17760  {
17761  int NewTVPos = Track->TrackElementAt(826, TVPos).Conn[LkPos]; //see above
17762  int NewLkPos = -1;
17763  if(NewTVPos > -1)
17764  {
17765  NewLkPos = Track->TrackElementAt(827, TVPos).ConnLinkPos[LkPos]; // this is the entry link pos
17766  if(NewLkPos == -1)
17767  {
17768  Utilities->CallLogPop(1840);
17769  return true; // shouldn't arise but treat as loop if does
17770  }
17771  }
17772  else // reached a buffer or continuation
17773  {
17774  Utilities->CallLogPop(1841);
17775  return false;
17776  }
17777 //Error found by Xeon notified by email 13/10/20.
17778 //Need to make sure there is a route with the new entry link NewLkPos on the next element (TrackIsInARoute normally used where it doesn't matter which track a route
17779 //is on - except for bridges). But here a route can end at a trailing point leg or a crossover and if so it doesn't link to the route on the other track, and needs to
17780 //return false. Without the new check below the program gets stuck in an endless loop, which is the error that Xeon found.
17781 //If there isn't a route at all on the next element then it would return false at the next iteration so can return false here.
17782 //New check added for v2.6.0
17783 //Note: Could probably use GetRouteTypeAndNumber in place of TrackIsInARoute in the while statement above and dispense with this new check, but I prefer to keep mods as simple
17784 //as possible in case there are other unforeseen effects.
17785  int RouteNumber; //dummy, not used
17786  if(GetRouteTypeAndNumber(36, NewTVPos, NewLkPos, RouteNumber) == NoRoute)
17787  {
17788  Utilities->CallLogPop(2241);
17789  return false;
17790  }
17791  //now make the connected element the current element, read across the TV number and determine the exit link
17792  TVPos = NewTVPos;
17793  if(Track->TrackElementAt(828, TVPos).TrackType == Points)
17794  {
17795  if((NewLkPos == 0) || (NewLkPos == 2)) // leading points
17796  {
17797  if(Track->TrackElementAt(829, TVPos).Attribute == 0)
17798  LkPos = 1;
17799  else
17800  LkPos = 3;
17801  }
17802  else
17803  LkPos = 0;
17804  }
17805  else
17806  LkPos = Track->GetNonPointsOppositeLinkPos(NewLkPos);
17807  if(TVPos == StartPosition)
17808  {
17809  Utilities->CallLogPop(1842);
17810  return true; // it is a loop
17811  }
17812  }
17813  Utilities->CallLogPop(1843);
17814  return false; // reached end of route so not a loop
17815 }
17816 
17817 // ---------------------------------------------------------------------------
17818 
17819 bool TAllRoutes::DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
17820 /*
17821  Track geometry allows diagonals to cross without occupying the same track element, so when
17822  route plotting it is necessary to check if there is an existing route or a train on such a crossing
17823  diagonal. Returns true for a fouled diagonal. Enter with H & V set for the element whose diagonal
17824  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
17825  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
17826  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
17827  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
17828  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
17829  Each of these is examined in turn for each route element in the relevant position.
17830 
17831  NOTE: Originally this failed to detect a train fouling a diagonal. v1.2.0 checks for a train present on a
17832  crossing diagonal element using a new bool function TTrack::TrainOnLink(int HLoc, int VLoc, int Link)
17833  that returns false in all cases (including elements & links not present) except train present.
17834 */
17835 {
17836  int TrainID; // not used in this function
17837 
17838  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRouteOrTrain," + AnsiString(HLoc) + "," +
17839  AnsiString(VLoc) + "," + AnsiString(DiagonalLinkNumber));
17840  TPrefDirElement TempPrefDirElement;
17841  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
17842 
17843  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(4, HLoc - 1, VLoc, SecondPair);
17844  if(FirstPair.first > -1)
17845  {
17846  TempPrefDirElement = AllRoutes->GetFixedRouteAt(50, FirstPair.first).GetFixedPrefDirElementAt(70, FirstPair.second);
17847  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17848  {
17849  Utilities->CallLogPop(310);
17850  return true;
17851  }
17852  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17853  {
17854  Utilities->CallLogPop(311);
17855  return true;
17856  }
17857  }
17858  if(SecondPair.first > -1)
17859  {
17860  TempPrefDirElement = AllRoutes->GetFixedRouteAt(51, SecondPair.first).GetFixedPrefDirElementAt(71, SecondPair.second);
17861  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17862  {
17863  Utilities->CallLogPop(312);
17864  return true;
17865  }
17866  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17867  {
17868  Utilities->CallLogPop(313);
17869  return true;
17870  }
17871  }
17872 
17873  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(0, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && Track->TrainOnLink(1, HLoc - 1, VLoc,
17874  9, TrainID)))
17875  {
17876  Utilities->CallLogPop(1997);
17877  return true;
17878  }
17879 
17880  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(5, HLoc, VLoc - 1, SecondPair);
17881  if(FirstPair.first > -1)
17882  {
17883  TempPrefDirElement = AllRoutes->GetFixedRouteAt(52, FirstPair.first).GetFixedPrefDirElementAt(72, FirstPair.second);
17884  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17885  {
17886  Utilities->CallLogPop(314);
17887  return true;
17888  }
17889  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17890  {
17891  Utilities->CallLogPop(315);
17892  return true;
17893  }
17894  }
17895  if(SecondPair.first > -1)
17896  {
17897  TempPrefDirElement = AllRoutes->GetFixedRouteAt(53, SecondPair.first).GetFixedPrefDirElementAt(73, SecondPair.second);
17898  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17899  {
17900  Utilities->CallLogPop(316);
17901  return true;
17902  }
17903  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17904  {
17905  Utilities->CallLogPop(317);
17906  return true;
17907  }
17908  }
17909 
17910  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(2, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && Track->TrainOnLink(3, HLoc, VLoc - 1,
17911  9, TrainID)))
17912  {
17913  Utilities->CallLogPop(1998);
17914  return true;
17915  }
17916 
17917  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(6, HLoc + 1, VLoc, SecondPair);
17918  if(FirstPair.first > -1)
17919  {
17920  TempPrefDirElement = AllRoutes->GetFixedRouteAt(54, FirstPair.first).GetFixedPrefDirElementAt(74, FirstPair.second);
17921  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17922  {
17923  Utilities->CallLogPop(318);
17924  return true;
17925  }
17926  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17927  {
17928  Utilities->CallLogPop(319);
17929  return true;
17930  }
17931  }
17932  if(SecondPair.first > -1)
17933  {
17934  TempPrefDirElement = AllRoutes->GetFixedRouteAt(55, SecondPair.first).GetFixedPrefDirElementAt(75, SecondPair.second);
17935  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17936  {
17937  Utilities->CallLogPop(320);
17938  return true;
17939  }
17940  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17941  {
17942  Utilities->CallLogPop(321);
17943  return true;
17944  }
17945  }
17946 
17947  if(((DiagonalLinkNumber == 3) && Track->TrainOnLink(4, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(5, HLoc + 1, VLoc,
17948  7, TrainID)))
17949  {
17950  Utilities->CallLogPop(1999);
17951  return true;
17952  }
17953 
17954  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(7, HLoc, VLoc + 1, SecondPair);
17955  if(FirstPair.first > -1)
17956  {
17957  TempPrefDirElement = AllRoutes->GetFixedRouteAt(56, FirstPair.first).GetFixedPrefDirElementAt(76, FirstPair.second);
17958  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17959  {
17960  Utilities->CallLogPop(322);
17961  return true;
17962  }
17963  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17964  {
17965  Utilities->CallLogPop(323);
17966  return true;
17967  }
17968  }
17969  if(SecondPair.first > -1)
17970  {
17971  TempPrefDirElement = AllRoutes->GetFixedRouteAt(57, SecondPair.first).GetFixedPrefDirElementAt(77, SecondPair.second);
17972  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17973  {
17974  Utilities->CallLogPop(324);
17975  return true;
17976  }
17977  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17978  {
17979  Utilities->CallLogPop(325);
17980  return true;
17981  }
17982  }
17983 
17984  if(((DiagonalLinkNumber == 7) && Track->TrainOnLink(6, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(7, HLoc, VLoc + 1,
17985  3, TrainID)))
17986  {
17987  Utilities->CallLogPop(2000);
17988  return true;
17989  }
17990 
17991  Utilities->CallLogPop(326);
17992  return false;
17993 }
17994 
17995 // ---------------------------------------------------------------------------
17996 
17997 bool TAllRoutes::DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
17998 /*
17999  As above but checks for a route only (may or may not be a train). Enter with H & V set for the element whose diagonal
18000  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
18001  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
18002  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
18003  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
18004  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
18005  Each of these is examined in turn for each route element in the relevant position.
18006 */
18007 {
18008  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
18009  "," + AnsiString(DiagonalLinkNumber));
18010  TPrefDirElement TempPrefDirElement;
18011  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
18012 
18013  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(17, HLoc - 1, VLoc, SecondPair);
18014  if(FirstPair.first > -1)
18015  {
18016  TempPrefDirElement = AllRoutes->GetFixedRouteAt(197, FirstPair.first).GetFixedPrefDirElementAt(233, FirstPair.second);
18017  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
18018  {
18019  Utilities->CallLogPop(2010);
18020  return true;
18021  }
18022  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
18023  {
18024  Utilities->CallLogPop(2011);
18025  return true;
18026  }
18027  }
18028  if(SecondPair.first > -1)
18029  {
18030  TempPrefDirElement = AllRoutes->GetFixedRouteAt(198, SecondPair.first).GetFixedPrefDirElementAt(234, SecondPair.second);
18031  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
18032  {
18033  Utilities->CallLogPop(2012);
18034  return true;
18035  }
18036  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
18037  {
18038  Utilities->CallLogPop(2013);
18039  return true;
18040  }
18041  }
18042 
18043  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(18, HLoc, VLoc - 1, SecondPair);
18044  if(FirstPair.first > -1)
18045  {
18046  TempPrefDirElement = AllRoutes->GetFixedRouteAt(199, FirstPair.first).GetFixedPrefDirElementAt(235, FirstPair.second);
18047  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
18048  {
18049  Utilities->CallLogPop(2014);
18050  return true;
18051  }
18052  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
18053  {
18054  Utilities->CallLogPop(2015);
18055  return true;
18056  }
18057  }
18058  if(SecondPair.first > -1)
18059  {
18060  TempPrefDirElement = AllRoutes->GetFixedRouteAt(200, SecondPair.first).GetFixedPrefDirElementAt(236, SecondPair.second);
18061  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
18062  {
18063  Utilities->CallLogPop(2016);
18064  return true;
18065  }
18066  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
18067  {
18068  Utilities->CallLogPop(2017);
18069  return true;
18070  }
18071  }
18072 
18073  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(19, HLoc + 1, VLoc, SecondPair);
18074  if(FirstPair.first > -1)
18075  {
18076  TempPrefDirElement = AllRoutes->GetFixedRouteAt(201, FirstPair.first).GetFixedPrefDirElementAt(237, FirstPair.second);
18077  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
18078  {
18079  Utilities->CallLogPop(2018);
18080  return true;
18081  }
18082  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
18083  {
18084  Utilities->CallLogPop(2019);
18085  return true;
18086  }
18087  }
18088  if(SecondPair.first > -1)
18089  {
18090  TempPrefDirElement = AllRoutes->GetFixedRouteAt(202, SecondPair.first).GetFixedPrefDirElementAt(238, SecondPair.second);
18091  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
18092  {
18093  Utilities->CallLogPop(2020);
18094  return true;
18095  }
18096  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
18097  {
18098  Utilities->CallLogPop(2021);
18099  return true;
18100  }
18101  }
18102 
18103  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(20, HLoc, VLoc + 1, SecondPair);
18104  if(FirstPair.first > -1)
18105  {
18106  TempPrefDirElement = AllRoutes->GetFixedRouteAt(203, FirstPair.first).GetFixedPrefDirElementAt(239, FirstPair.second);
18107  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
18108  {
18109  Utilities->CallLogPop(2022);
18110  return true;
18111  }
18112  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
18113  {
18114  Utilities->CallLogPop(2023);
18115  return true;
18116  }
18117  }
18118  if(SecondPair.first > -1)
18119  {
18120  TempPrefDirElement = AllRoutes->GetFixedRouteAt(204, SecondPair.first).GetFixedPrefDirElementAt(240, SecondPair.second);
18121  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
18122  {
18123  Utilities->CallLogPop(2024);
18124  return true;
18125  }
18126  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
18127  {
18128  Utilities->CallLogPop(2025);
18129  return true;
18130  }
18131  }
18132 
18133  Utilities->CallLogPop(2026);
18134  return false;
18135 }
18136 
18137 // ---------------------------------------------------------------------------
TTrain::LinkOccupied
bool LinkOccupied(int Caller, int TrackVectorPosition, int LinkNumber)
Added at v1.2.0: true if any part of train on specific link, false otherwise, including no link prese...
Definition: TrainUnit.cpp:7642
TRailGraphics::gl70
Graphics::TBitmap * gl70
Definition: GraphicUnit.h:676
TRailGraphics::bm72CallingOn
Graphics::TBitmap * bm72CallingOn
Definition: GraphicUnit.h:476
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:16268
TPrefDirRoute
TPrefDirRoute
< used in TOnePrefDir::PrefDirMarker to indicate whether the function is being called for a preferred...
Definition: TrackUnit.h:1185
TRailGraphics::sm120
Graphics::TBitmap * sm120
Definition: GraphicUnit.h:915
TRailGraphics::bm7
Graphics::TBitmap * bm7
Definition: GraphicUnit.h:463
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:10384
TRailGraphics::gl58
Graphics::TBitmap * gl58
Definition: GraphicUnit.h:662
TRailGraphics::LCLHSVerMan
Graphics::TBitmap * LCLHSVerMan
Definition: GraphicUnit.h:729
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:36
TRailGraphics::gl145
Graphics::TBitmap * gl145
Definition: GraphicUnit.h:612
TRailGraphics::gl102
Graphics::TBitmap * gl102
Definition: GraphicUnit.h:564
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:10357
TGraphicElement::HPos
int HPos
Definition: TrackUnit.h:351
TTrack::GapVLoc
int GapVLoc
record gap setting info
Definition: TrackUnit.h:485
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:50
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:80
TRailGraphics::bm11
Graphics::TBitmap * bm11
Definition: GraphicUnit.h:352
TRailGraphics::sm99
Graphics::TBitmap * sm99
Definition: GraphicUnit.h:874
TTrack::ResetGapsFromGapMap
bool ResetGapsFromGapMap(int Caller)
Called by RepositionAndMapTrack to reset the connecting elements of all set gaps (their TrackVector p...
Definition: TrackUnit.cpp:4943
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:11839
TRailGraphics::sm129
Graphics::TBitmap * sm129
Definition: GraphicUnit.h:771
TFixedTrackPiece
Definition: TrackUnit.h:80
TFixedTrackPiece::PlotFixedTrackElement
void PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
Plot the element on the railway display at position HLocInput & VLocInput.
Definition: TrackUnit.cpp:107
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1586
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:12928
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:182
TTrack::LNDone2MultiMap
TLNDone2MultiMap LNDone2MultiMap
multimap of processed location name elements (see type for more information above)
Definition: TrackUnit.h:699
TTextHandler::RebuildFromTextVector
void RebuildFromTextVector(int Caller, TDisplay *Disp)
display all text items in TextVector on the screen
Definition: TextUnit.cpp:408
TRailGraphics::sm72
Graphics::TBitmap * sm72
Definition: GraphicUnit.h:906
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:6713
TAllRoutes::Route2MultiMapInsert
void Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
Insert an entry in Route2MultiMap. Called by TAllRoutes::AddRouteElement.
Definition: TrackUnit.cpp:16871
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:90
TRailGraphics::sm2
Graphics::TBitmap * sm2
Definition: GraphicUnit.h:790
clB5G0R0
#define clB5G0R0
Definition: GraphicUnit.h:246
TRailGraphics::sm73
Graphics::TBitmap * sm73
Definition: GraphicUnit.h:907
TTrack::IsNamedNonStationLocationPresent
bool IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location at HLoc & VLoc.
Definition: TrackUnit.cpp:9044
TRailGraphics::sm21
Graphics::TBitmap * sm21
Definition: GraphicUnit.h:792
TAllRoutes::SetAllRearwardsSignals
void SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
Set rearwards signals from the specified route starting position.
Definition: TrackUnit.cpp:17277
TRailGraphics::sm123
Graphics::TBitmap * sm123
Definition: GraphicUnit.h:918
TOnePrefDir::SearchLimitLowV
int SearchLimitLowV
Definition: TrackUnit.h:1243
TRailGraphics::bm8
Graphics::TBitmap * bm8
Definition: GraphicUnit.h:508
TTrack::GapMap
TGapMap GapMap
map of gaps (see type for more information above)
Definition: TrackUnit.h:691
TRailGraphics::gl117
Graphics::TBitmap * gl117
Definition: GraphicUnit.h:580
TRailGraphics::gl89set
Graphics::TBitmap * gl89set
Definition: GraphicUnit.h:701
TOnePrefDir::ErasePrefDirElementAt
void ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNum...
Definition: TrackUnit.cpp:12098
TRailGraphics::sm104
Graphics::TBitmap * sm104
Definition: GraphicUnit.h:758
TRailGraphics::gl19
Graphics::TBitmap * gl19
Definition: GraphicUnit.h:619
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:706
TGraphicElement::ScreenSourceSet
bool ScreenSourceSet
Definition: TrackUnit.h:349
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:11879
TRailGraphics::gl72
Graphics::TBitmap * gl72
Definition: GraphicUnit.h:678
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3579
TRailGraphics::gl88set
Graphics::TBitmap * gl88set
Definition: GraphicUnit.h:699
TRailGraphics::bm28
Graphics::TBitmap * bm28
Definition: GraphicUnit.h:394
TRailGraphics::bm68grounddblred
Graphics::TBitmap * bm68grounddblred
Definition: GraphicUnit.h:453
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:14343
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:689
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:289
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:6566
TAllRoutes::TLockedRouteClass::TruncateTrackVectorPosition
unsigned int TruncateTrackVectorPosition
the TrackVector position of the element selected for truncation
Definition: TrackUnit.h:1504
TRailGraphics::bm70grounddblred
Graphics::TBitmap * bm70grounddblred
Definition: GraphicUnit.h:466
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:48
TRailGraphics::gl75
Graphics::TBitmap * gl75
Definition: GraphicUnit.h:683
TAllRoutes::LockedRouteLockStartTime
TDateTime LockedRouteLockStartTime
Definition: TrackUnit.h:1566
TTrack::TSigElement::Attribute
int Attribute
the signal state - red, yellow, double yellow or green
Definition: TrackUnit.h:625
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5079
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5106
TOneRoute::TRouteFlash::OverlayPlotted
bool OverlayPlotted
flag indicating the graphic that is currently displayed, true for the overlay (route-coloured)
Definition: TrackUnit.h:1389
TTrack::LeftPlatAllowed
Set< int, 1, 146 > LeftPlatAllowed
Definition: TrackUnit.h:505
TAllRoutes::TRouteElementPair
std::pair< int, unsigned int > TRouteElementPair
defines a specific element in a route, the first (int) value is the vector position in the AllRoutesV...
Definition: TrackUnit.h:1527
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:64
TRailGraphics::sm51
Graphics::TBitmap * sm51
Definition: GraphicUnit.h:825
TRailGraphics::sm77
Graphics::TBitmap * sm77
Definition: GraphicUnit.h:846
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1645
TPrefDirElement::GetRouteAutoSigsGraphicPtr
Graphics::TBitmap * GetRouteAutoSigsGraphicPtr()
picks up the blue route graphic (not used - superseded by GetRouteGraphicPtr)
Definition: TrackUnit.cpp:741
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:9356
TTrack::TActiveLevelCrossing::ReducedTimePenalty
bool ReducedTimePenalty
marker that is set when a train is present on one of the elements of the LC - used to provide a 3 min...
Definition: TrackUnit.h:532
TOneRoute::FindForwardTargetSignalAttribute
bool FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
Used when setting signal aspects for a route by working forwards through the route to see what the ne...
Definition: TrackUnit.cpp:15580
TRailGraphics::gl143
Graphics::TBitmap * gl143
Definition: GraphicUnit.h:611
TRailGraphics::sm70
Graphics::TBitmap * sm70
Definition: GraphicUnit.h:904
TAllRoutes::DiagonalFouledByRoute
bool DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
As above but only checks for a route (may or may not be a train present (new at v1....
Definition: TrackUnit.cpp:17997
TGraphicElement::VPos
int VPos
horizontal and vertical positions
Definition: TrackUnit.h:351
TAllRoutes::LockedRouteFoundDuringRouteBuilding
bool LockedRouteFoundDuringRouteBuilding
this flags the fact that a locked route has been found during route building in an existing linked ro...
Definition: TrackUnit.h:1557
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:69
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:523
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2449
TRailGraphics::bm73CallingOn
Graphics::TBitmap * bm73CallingOn
Definition: GraphicUnit.h:483
TTrack::TFixedTrackArray::FixedTrackPiece
TFixedTrackPiece FixedTrackPiece[FirstUnusedSpeedTagNumber]
the array member
Definition: TrackUnit.h:470
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:5235
TRailGraphics::LCBotHorMan
Graphics::TBitmap * LCBotHorMan
Definition: GraphicUnit.h:727
TRailGraphics::gl66
Graphics::TBitmap * gl66
Definition: GraphicUnit.h:671
TRailGraphics::bm69grounddblred
Graphics::TBitmap * bm69grounddblred
Definition: GraphicUnit.h:459
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Used for track at platforms and non-station named locations to mark the train front element stop posi...
Definition: TrackUnit.h:149
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:7356
TOneRoute::RouteSearchLimit
static const int RouteSearchLimit
limit to the number of elements searched in attempting to find a route
Definition: TrackUnit.h:1399
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:384
TTrack::TTrackVectorIterator
std::vector< TTrackElement >::iterator TTrackVectorIterator
iterator for TTrackVector
Definition: TrackUnit.h:561
TAllRoutes::ClearRouteDuringRouteBuildingAt
void ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
When attaching a new route section to an existing route, it is sometimes necessary to erase the origi...
Definition: TrackUnit.cpp:16704
TRailGraphics::sm108
Graphics::TBitmap * sm108
Definition: GraphicUnit.h:762
TTrack::Tag79Array
int Tag79Array[25][3]
Definition: TrackUnit.h:497
TRailGraphics::gl60
Graphics::TBitmap * gl60
Definition: GraphicUnit.h:665
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:11636
TRailGraphics::bm132
Graphics::TBitmap * bm132
Definition: GraphicUnit.h:359
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:6859
TRailGraphics::bm73
Graphics::TBitmap * bm73
Definition: GraphicUnit.h:482
TRailGraphics::bm30
Graphics::TBitmap * bm30
Definition: GraphicUnit.h:400
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:8653
TTrack::DecrementValuesInGapsAndTrackAndNameMaps
void DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the TrackVector, all the later elements are moved down one....
Definition: TrackUnit.cpp:8541
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:12729
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:48
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:14030
TRailGraphics::gl103
Graphics::TBitmap * gl103
Definition: GraphicUnit.h:565
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:17065
TRailGraphics::sm83
Graphics::TBitmap * sm83
Definition: GraphicUnit.h:856
TRailGraphics::sm81
Graphics::TBitmap * sm81
Definition: GraphicUnit.h:854
TRailGraphics::bm74grounddblwhite
Graphics::TBitmap * bm74grounddblwhite
Definition: GraphicUnit.h:493
TAllRoutes::TLockedRouteClass::LastXLinkPos
int LastXLinkPos
the XLinkPos value of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1508
TRailGraphics::sm97
Graphics::TBitmap * sm97
Definition: GraphicUnit.h:872
TRailGraphics::Concourse
Graphics::TBitmap * Concourse
Definition: GraphicUnit.h:547
TOnePrefDir::LoadOldPrefDir
void LoadOldPrefDir(int Caller, std::ifstream &VecFile)
Old version of LoadPrefDir, used during development when the save format changed so the old files cou...
Definition: TrackUnit.cpp:11440
TTrackElement::FourAspect
@ FourAspect
Definition: TrackUnit.h:156
TRailGraphics::bm9
Graphics::TBitmap * bm9
Definition: GraphicUnit.h:512
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:4005
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3264
TRailGraphics::gl67
Graphics::TBitmap * gl67
Definition: GraphicUnit.h:672
TRailGraphics::sm56
Graphics::TBitmap * sm56
Definition: GraphicUnit.h:830
TOneRoute::StartRoutePosition
int StartRoutePosition
TrackVectorPosition of the StartElement(s) set when the starting position of a new route is selected,...
Definition: TrackUnit.h:1411
TRailGraphics::bm69dblyellow
Graphics::TBitmap * bm69dblyellow
Definition: GraphicUnit.h:458
TRailGraphics::gl118
Graphics::TBitmap * gl118
Definition: GraphicUnit.h:581
TRailGraphics::sm105
Graphics::TBitmap * sm105
Definition: GraphicUnit.h:759
TRailGraphics::bm70dblyellow
Graphics::TBitmap * bm70dblyellow
Definition: GraphicUnit.h:465
TRailGraphics::sm24
Graphics::TBitmap * sm24
Definition: GraphicUnit.h:795
TTrack::CheckFootCrossingLinks
bool CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
True if a footcrossing is linked properly at both ends.
Definition: TrackUnit.cpp:7173
TGraphicElement::SourceRect
TRect SourceRect
source rectangle of the original graphic
Definition: TrackUnit.h:357
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:164
TRailGraphics::gl57
Graphics::TBitmap * gl57
Definition: GraphicUnit.h:661
TRailGraphics::gl120
Graphics::TBitmap * gl120
Definition: GraphicUnit.h:584
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4164
TOnePrefDir::TPrefDir4MultiMapEntry
std::pair< THVPair, unsigned int > TPrefDir4MultiMapEntry
Definition: TrackUnit.h:1199
TTrack::OneNamedLocationElementAtLocation
bool OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
True if there is at least one named location element with name 'LocationName', used in timetable inte...
Definition: TrackUnit.cpp:9790
TRailGraphics::gl5
Graphics::TBitmap * gl5
Definition: GraphicUnit.h:653
TRailGraphics::bm94unset
Graphics::TBitmap * bm94unset
Definition: GraphicUnit.h:516
TRailGraphics::sm93
Graphics::TBitmap * sm93
Definition: GraphicUnit.h:867
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3140
Unused
@ Unused
Definition: TrackUnit.h:63
TRailGraphics::gl122
Graphics::TBitmap * gl122
Definition: GraphicUnit.h:586
TRailGraphics::gl15
Graphics::TBitmap * gl15
Definition: GraphicUnit.h:616
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TOnePrefDir::TPrefDir4MultiMapIterator
std::multimap< THVPair, unsigned int, TMapComp >::iterator TPrefDir4MultiMapIterator
Definition: TrackUnit.h:1198
TRailGraphics::bm74
Graphics::TBitmap * bm74
Definition: GraphicUnit.h:489
TRailGraphics::gl90set
Graphics::TBitmap * gl90set
Definition: GraphicUnit.h:704
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:17517
TrackUnit.h
TTrack::ReturnNextInactiveTrackElement
bool ReturnNextInactiveTrackElement(int Caller, TTrackElement &Next)
Return a reference to the inactive track element pointed to by NextTrackElementPtr (during zoomed-in ...
Definition: TrackUnit.cpp:2480
TRailGraphics::sm117
Graphics::TBitmap * sm117
Definition: GraphicUnit.h:769
TPrefDirElement::IsARoute
bool IsARoute
false for Pref Dir, true for route
Definition: TrackUnit.h:252
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:17708
TTrack::Tag76Array
int Tag76Array[25][3]
these arrays give valid adjacent named element relative positions for each type of named element,...
Definition: TrackUnit.h:493
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:8698
TAllRoutes::LockedRouteLastTrackVectorPosition
unsigned int LockedRouteLastTrackVectorPosition
Definition: TrackUnit.h:1565
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1409
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1495
TPrefDirElement::TrackVectorPosition
int TrackVectorPosition
TrackVectorPosition of the corresponding track element.
Definition: TrackUnit.h:219
TRailGraphics::sm121
Graphics::TBitmap * sm121
Definition: GraphicUnit.h:916
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:34
Utilities.h
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:665
TGraphicElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:355
TRailGraphics::sm46
Graphics::TBitmap * sm46
Definition: GraphicUnit.h:819
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:2868
TOneRoute::SetLCChangeValues
void SetLCChangeValues(int Caller, bool ConsecSignalsRoute)
After a route has been selected successfully this function sets all LC change values appropriately fo...
Definition: TrackUnit.cpp:16092
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:34
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:221
TRailGraphics::sm131striped
Graphics::TBitmap * sm131striped
Definition: GraphicUnit.h:776
TRailGraphics::gl63
Graphics::TBitmap * gl63
Definition: GraphicUnit.h:668
TRailGraphics::bm75grounddblwhite
Graphics::TBitmap * bm75grounddblwhite
Definition: GraphicUnit.h:499
TTrack::AdjElement
bool AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
Definition: TrackUnit.cpp:7617
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:11702
Simple
@ Simple
Definition: TrackUnit.h:63
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:693
TRailGraphics::bm46
Graphics::TBitmap * bm46
Definition: GraphicUnit.h:443
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:40
TRailGraphics::bm72dblyellow
Graphics::TBitmap * bm72dblyellow
Definition: GraphicUnit.h:477
TRailGraphics::sm22
Graphics::TBitmap * sm22
Definition: GraphicUnit.h:793
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2496
TTrack::TSigElement::SigPtr
Graphics::TBitmap * SigPtr
pointer to the graphic
Definition: TrackUnit.h:627
TRailGraphics::BridgeNonSigRouteGraphicsPtr
Graphics::TBitmap * BridgeNonSigRouteGraphicsPtr[12]
route graphic for unrestricted route overlay
Definition: GraphicUnit.h:1004
TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors
bool FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber)
If a route is present at H, V & Elink returns true with RouteNumber giving vector position in AllRout...
Definition: TrackUnit.cpp:16816
TRailGraphics::sm130
Graphics::TBitmap * sm130
Definition: GraphicUnit.h:774
TRailGraphics::sm45
Graphics::TBitmap * sm45
Definition: GraphicUnit.h:818
TRailGraphics::bm38
Graphics::TBitmap * bm38
Definition: GraphicUnit.h:424
TOnePrefDir::TPrefDirVectorIterator
std::vector< TPrefDirElement >::iterator TPrefDirVectorIterator
Definition: TrackUnit.h:1231
TRailGraphics::gl90unset
Graphics::TBitmap * gl90unset
Definition: GraphicUnit.h:705
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:11930
TGraphicElement::TGraphicElement
TGraphicElement()
Default constructor (16 x 16 pixel element)
Definition: TrackUnit.cpp:1453
TRailGraphics::gl129Striped
Graphics::TBitmap * gl129Striped
Definition: GraphicUnit.h:594
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5195
TRailGraphics::gl64
Graphics::TBitmap * gl64
Definition: GraphicUnit.h:669
TTrain
Definition: TrainUnit.h:271
TPrefDirElement::TPrefDirElement
TPrefDirElement()
Default constructor, loads default values.
Definition: TrackUnit.h:313
TOnePrefDir::PresetAutoRouteDiagonalFouledByTrack
bool PresetAutoRouteDiagonalFouledByTrack(int Caller, TPrefDirElement ElementIn, int XLink)
Called by GetStartAndEndPrefDirElements...
Definition: TrackUnit.cpp:12596
TRailGraphics::bm77Striped
Graphics::TBitmap * bm77Striped
Definition: GraphicUnit.h:503
TFixedTrackPiece::TFixedTrackPiece
TFixedTrackPiece()
Default constructor.
Definition: TrackUnit.cpp:96
TTrackElement::TrainIDOnBridgeTrackPos23
int TrainIDOnBridgeTrackPos23
Set to the TrainID value when a train is present on the element, bridges can have two trains present ...
Definition: TrackUnit.h:151
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:10398
TRailGraphics::bm74grounddblred
Graphics::TBitmap * bm74grounddblred
Definition: GraphicUnit.h:492
TRailGraphics::gl1
Graphics::TBitmap * gl1
Definition: GraphicUnit.h:560
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int ConsecSignals, TDisplay *Disp, bool Manual)
Plot & open (to trains) all level crossings linked to TrackElement (Manual true = manually lowered,...
Definition: TrackUnit.cpp:5765
TTrack::LinkCheckArray
int LinkCheckArray[9][2]
array of valid link connecting values, I don't think this is used now
Definition: TrackUnit.h:489
TRailGraphics::sm66
Graphics::TBitmap * sm66
Definition: GraphicUnit.h:841
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:542
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:6874
TRailGraphics::bm35
Graphics::TBitmap * bm35
Definition: GraphicUnit.h:415
TRailGraphics::bm10
Graphics::TBitmap * bm10
Definition: GraphicUnit.h:346
GapJump
@ GapJump
Definition: TrackUnit.h:63
TRailGraphics::bm45
Graphics::TBitmap * bm45
Definition: GraphicUnit.h:442
TRailGraphics::sm19
Graphics::TBitmap * sm19
Definition: GraphicUnit.h:789
TAllRoutes::AddRouteElement
void AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2Mult...
Definition: TrackUnit.cpp:17175
TOneRoute::SetRouteSearchVectorGraphics
void SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool ConsecSignalsRoute)
Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector so that the...
Definition: TrackUnit.cpp:16041
TRailGraphics::sm82
Graphics::TBitmap * sm82
Definition: GraphicUnit.h:855
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:147
TRailGraphics::bm71dblyellow
Graphics::TBitmap * bm71dblyellow
Definition: GraphicUnit.h:471
TRailGraphics::sm124
Graphics::TBitmap * sm124
Definition: GraphicUnit.h:919
TRailGraphics::bm69CallingOn
Graphics::TBitmap * bm69CallingOn
Definition: GraphicUnit.h:457
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:147
TTrack::Raising
@ Raising
Definition: TrackUnit.h:523
TRailGraphics::gl26
Graphics::TBitmap * gl26
Definition: GraphicUnit.h:627
TTrack::VLocMax
int VLocMax
give extent of railway for use in zoomed in and out displays and in saving railway images
Definition: TrackUnit.h:487
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:9425
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:557
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:78
TOneRoute::StartElement2
TPrefDirElement StartElement2
the two preferred direction elements corresponding to the starting position of a new route
Definition: TrackUnit.h:1413
TOneRoute::TRouteFlashElement::VLoc
int VLoc
Definition: TrackUnit.h:1377
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool ConsecSignalsRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:16064
TRailGraphics::gl86
Graphics::TBitmap * gl86
Definition: GraphicUnit.h:697
TRailGraphics::bm134
Graphics::TBitmap * bm134
Definition: GraphicUnit.h:365
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:638
TTrack::Tag129Array
int Tag129Array[8][3]
Definition: TrackUnit.h:499
TTrack::InactiveTrack2MultiMap
TInactiveTrack2MultiMap InactiveTrack2MultiMap
multimap of inactive TrackElements (see type for more information above)
Definition: TrackUnit.h:695
TRailGraphics::bm14
Graphics::TBitmap * bm14
Definition: GraphicUnit.h:385
TRailGraphics::sm106
Graphics::TBitmap * sm106
Definition: GraphicUnit.h:760
TRailGraphics::bm68dblyellow
Graphics::TBitmap * bm68dblyellow
Definition: GraphicUnit.h:452
TRailGraphics::gl97
Graphics::TBitmap * gl97
Definition: GraphicUnit.h:714
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1275
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:5426
End
@ End
Definition: TrackUnit.h:73
TUserGraphicItem
Definition: DisplayUnit.h:31
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1415
TRailGraphics::gl62
Graphics::TBitmap * gl62
Definition: GraphicUnit.h:667
TRailGraphics::sm67
Graphics::TBitmap * sm67
Definition: GraphicUnit.h:842
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers
Definition: TrackUnit.h:534
TTrack::TimetabledLocationNameAllocated
bool TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found as a timetabled location name i.e. not as a continuation name.
Definition: TrackUnit.cpp:7965
TRailGraphics::sm9
Graphics::TBitmap * sm9
Definition: GraphicUnit.h:863
TTrack::LCFoundInAutoSigsRouteMessageGiven
bool LCFoundInAutoSigsRouteMessageGiven
true if message given to user, to avoid giving multiple times and to avoid other failure messages bei...
Definition: TrackUnit.h:654
TRailGraphics::sm68
Graphics::TBitmap * sm68
Definition: GraphicUnit.h:902
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:41
TTrack::TrackFinished
bool TrackFinished
marker for all Conn & ConnLinkPos values set & track complete
Definition: TrackUnit.h:482
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackElement.at(At)
Definition: TrackUnit.cpp:9531
TRailGraphics::LinkNonSigRouteGraphicsPtr
Graphics::TBitmap * LinkNonSigRouteGraphicsPtr[30]
unrestricted route graphic overlay
Definition: GraphicUnit.h:1017
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:295
TRailGraphics::sm28
Graphics::TBitmap * sm28
Definition: GraphicUnit.h:799
TTrack::RouteFailMessage
AnsiString RouteFailMessage
Definition: TrackUnit.h:640
clB0G5R0
#define clB0G5R0
Definition: GraphicUnit.h:71
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:701
TRailGraphics::gl114
Graphics::TBitmap * gl114
Definition: GraphicUnit.h:577
TRailGraphics::sm116
Graphics::TBitmap * sm116
Definition: GraphicUnit.h:912
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:123
TRailGraphics::LCLHSVer
Graphics::TBitmap * LCLHSVer
Definition: GraphicUnit.h:722
TRailGraphics::bm74dblyellow
Graphics::TBitmap * bm74dblyellow
Definition: GraphicUnit.h:491
TRailGraphics::sm103
Graphics::TBitmap * sm103
Definition: GraphicUnit.h:757
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3423
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:988
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:757
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:989
TRailGraphics::bmNameStriped
Graphics::TBitmap * bmNameStriped
Definition: GraphicUnit.h:524
TRailGraphics::gl88unset
Graphics::TBitmap * gl88unset
Definition: GraphicUnit.h:700
SignalPost
@ SignalPost
Definition: TrackUnit.h:63
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:8663
TRailGraphics::BridgeGraphicsPtr
Graphics::TBitmap * BridgeGraphicsPtr[12]
basic graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:998
TRailGraphics::bm69green
Graphics::TBitmap * bm69green
Definition: GraphicUnit.h:461
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:16218
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:421
TRailGraphics::sm132
Graphics::TBitmap * sm132
Definition: GraphicUnit.h:777
TPrefDirElement::operator!=
bool operator!=(TPrefDirElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:863
TTrack::TActiveLevelCrossing::ConsecSignals
int ConsecSignals
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs), 2 no route,...
Definition: TrackUnit.h:530
TAllRoutes::TRoute2MultiMapIterator
TRoute2MultiMap::iterator TRoute2MultiMapIterator
Definition: TrackUnit.h:1531
TRailGraphics::sm20
Graphics::TBitmap * sm20
Definition: GraphicUnit.h:791
TRailGraphics::sm52
Graphics::TBitmap * sm52
Definition: GraphicUnit.h:826
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:6888
TRailGraphics::bm68yellow
Graphics::TBitmap * bm68yellow
Definition: GraphicUnit.h:456
TTrack::TInactiveTrackRange
std::pair< TInactiveTrack2MultiMapIterator, TInactiveTrack2MultiMapIterator > TInactiveTrackRange
range for TInactiveTrack2MultiMap
Definition: TrackUnit.h:583
TRailGraphics::bm31
Graphics::TBitmap * bm31
Definition: GraphicUnit.h:403
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway (...
Definition: TrackUnit.cpp:6170
TPrefDirElement::AutoSignals
bool AutoSignals
marker within the route for an AutoSignal route element
Definition: TrackUnit.h:254
TRailGraphics::bm74CallingOn
Graphics::TBitmap * bm74CallingOn
Definition: GraphicUnit.h:490
TRailGraphics::gl76
Graphics::TBitmap * gl76
Definition: GraphicUnit.h:684
FirstUnusedSpeedTagNumber
#define FirstUnusedSpeedTagNumber
Definition: TrackUnit.h:36
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:8003
TRailGraphics::sm71
Graphics::TBitmap * sm71
Definition: GraphicUnit.h:905
TRailGraphics::sm43
Graphics::TBitmap * sm43
Definition: GraphicUnit.h:816
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir ...
Definition: TrackUnit.cpp:16203
TRailGraphics::sm101
Graphics::TBitmap * sm101
Definition: GraphicUnit.h:755
Concourse
@ Concourse
Definition: TrackUnit.h:64
TTrack::BotPlatAllowed
Set< int, 1, 146 > BotPlatAllowed
Definition: TrackUnit.h:505
TRailGraphics::gl52
Graphics::TBitmap * gl52
Definition: GraphicUnit.h:656
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:710
TRailGraphics::sm29
Graphics::TBitmap * sm29
Definition: GraphicUnit.h:800
TConfiguration
TConfiguration
< describes the type of track link. 'End' is used for both buffer stop and continuation entry/exit po...
Definition: TrackUnit.h:72
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:12386
TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap
void DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
Called after ErasePrefDirElementAt to decrement the remaining PrefDirElementNumbers in 4MultiMap if t...
Definition: TrackUnit.cpp:12124
TTrackElement::LogTrack
AnsiString LogTrack(int Caller) const
Used to log track parameters for call stack logging.
Definition: TrackUnit.cpp:202
TRailGraphics::gl95unset
Graphics::TBitmap * gl95unset
Definition: GraphicUnit.h:713
TTrack::TrackVectorSize
int TrackVectorSize()
Return the number of active track elements.
Definition: TrackUnit.h:806
TTrackType
TTrackType
< describes the type of track element
Definition: TrackUnit.h:62
TRailGraphics::bm77
Graphics::TBitmap * bm77
Definition: GraphicUnit.h:502
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4089
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1597
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:94
TRailGraphics::bm39
Graphics::TBitmap * bm39
Definition: GraphicUnit.h:427
TRailGraphics::sm40
Graphics::TBitmap * sm40
Definition: GraphicUnit.h:813
TRailGraphics::bm41
Graphics::TBitmap * bm41
Definition: GraphicUnit.h:433
TRailGraphics::sm54
Graphics::TBitmap * sm54
Definition: GraphicUnit.h:828
TRailGraphics::bm72green
Graphics::TBitmap * bm72green
Definition: GraphicUnit.h:480
TRailGraphics::gl129
Graphics::TBitmap * gl129
Definition: GraphicUnit.h:593
TRailGraphics::sm31
Graphics::TBitmap * sm31
Definition: GraphicUnit.h:803
TGraphicElement::ExistingGraphicLoaded
bool ExistingGraphicLoaded
state flags
Definition: TrackUnit.h:349
TRailGraphics::bm74green
Graphics::TBitmap * bm74green
Definition: GraphicUnit.h:494
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:35
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:675
TRailGraphics::bm71grounddblred
Graphics::TBitmap * bm71grounddblred
Definition: GraphicUnit.h:472
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TFixedTrackPiece::SmallGraphicPtr
Graphics::TBitmap * SmallGraphicPtr
the track bitmap for display on the zoomed-out railway
Definition: TrackUnit.h:92
TRailGraphics::bm40
Graphics::TBitmap * bm40
Definition: GraphicUnit.h:430
TRailGraphics::sm42
Graphics::TBitmap * sm42
Definition: GraphicUnit.h:815
TRailGraphics::gl111
Graphics::TBitmap * gl111
Definition: GraphicUnit.h:574
TTrack::IsATrackElementAdjacentToLink
bool IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
True if there is an element adjacent to LinkIn for element at HLoc & VLoc.
Definition: TrackUnit.cpp:9975
TAllRoutes::DecrementRouteNumbersInRoute2MultiMap
void DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
After a route has been erased from AllRoutesVector and its entries from Route2MultiMap,...
Definition: TrackUnit.cpp:17022
TOneRoute::GetRouteTruncateElement
void GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, TTruncateReturnType &ReturnFlag)
Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFl...
Definition: TrackUnit.cpp:15793
TTrack::BuildGapMapFromTrackVector
void BuildGapMapFromTrackVector(int Caller)
Examine TrackVector and whenever find a new gap pair enter it into GapMap.
Definition: TrackUnit.cpp:4322
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:156
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1616
TRailGraphics::gl68
Graphics::TBitmap * gl68
Definition: GraphicUnit.h:673
TRailGraphics::sm18
Graphics::TBitmap * sm18
Definition: GraphicUnit.h:788
TRailGraphics::sm128
Graphics::TBitmap * sm128
Definition: GraphicUnit.h:923
TTrack::FixedTrackArray
TFixedTrackArray FixedTrackArray
the FixedTrackPiece array object
Definition: TrackUnit.h:477
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:90
TRailGraphics::gl121
Graphics::TBitmap * gl121
Definition: GraphicUnit.h:585
TRailGraphics::LCBothHor
Graphics::TBitmap * LCBothHor
Definition: GraphicUnit.h:719
TRailGraphics::sm6
Graphics::TBitmap * sm6
Definition: GraphicUnit.h:834
TPrefDirElement::GetOriginalGraphicPtr
Graphics::TBitmap * GetOriginalGraphicPtr()
picks up the original (non-flashing) graphic for use during route flashing
Definition: TrackUnit.cpp:382
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
As DiagonalFouledByRouteOrTrain (in TAllRoutes) but only checks for a train (may or may not be a rout...
Definition: TrackUnit.cpp:10211
TAllRoutes::IsThereARouteAtIDNumber
bool IsThereARouteAtIDNumber(int Caller, IDInt RouteID)
Returns true if there is a route with the given ID number - added at v1.3.1 (see function for details...
Definition: TrackUnit.cpp:17614
TTrack::NameAllowed
Set< int, 1, 146 > NameAllowed
Definition: TrackUnit.h:505
TRailGraphics::LinkSigRouteGraphicsPtr
Graphics::TBitmap * LinkSigRouteGraphicsPtr[30]
preferred direction route graphic overlay
Definition: GraphicUnit.h:1015
TRailGraphics::gl142
Graphics::TBitmap * gl142
Definition: GraphicUnit.h:610
TTrack::ReturnNextTrackElement
bool ReturnNextTrackElement(int Caller, TTrackElement &Next)
Return a reference to the active track element pointed to by NextTrackElementPtr (during zoomed-in or...
Definition: TrackUnit.cpp:2464
TRailGraphics::gl92unset
Graphics::TBitmap * gl92unset
Definition: GraphicUnit.h:709
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1421
TTrack::ResetAllTrainIDElements
void ResetAllTrainIDElements(int Caller)
Track elements have members that indicates whether and on what track a train is present (TrainIDOnEle...
Definition: TrackUnit.cpp:6845
TOneRoute::RouteImageMarker
void RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
Used when creating a bitmap image to display the route colours and direction arrows (as on screen dur...
Definition: TrackUnit.cpp:13626
TTrack::IsLCBarrierUpAtHV
bool IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc)
True if a closed (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:6594
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:7807
TTrack::SetLCAttributeAtHV
void SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
Set LC attribute at H & V; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to tra...
Definition: TrackUnit.cpp:6673
TRailGraphics::gl61
Graphics::TBitmap * gl61
Definition: GraphicUnit.h:666
TRailGraphics::LCBotHor
Graphics::TBitmap * LCBotHor
Definition: GraphicUnit.h:720
TTrack::TLocationNameMultiMapEntry
std::pair< AnsiString, int > TLocationNameMultiMapEntry
Definition: TrackUnit.h:605
TRailGraphics::gl55
Graphics::TBitmap * gl55
Definition: GraphicUnit.h:659
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:50
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
km/h
Definition: TrainUnit.h:284
TTrack::TLNDone2MultiMapIterator
TLNDone2MultiMap::iterator TLNDone2MultiMapIterator
during naming of linked named location elements, '2' because there
Definition: TrackUnit.h:596
TOnePrefDir::PrefDir4MultiMap
TPrefDir4MultiMap PrefDir4MultiMap
the pref dir multimap - up to 4 values (up to 2 tracks per element each with 2 directions)
Definition: TrackUnit.h:1201
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:757
TRailGraphics::sm30
Graphics::TBitmap * sm30
Definition: GraphicUnit.h:802
TRailGraphics::bm85
Graphics::TBitmap * bm85
Definition: GraphicUnit.h:509
TRailGraphics::sm3
Graphics::TBitmap * sm3
Definition: GraphicUnit.h:801
TRailGraphics::bm70yellow
Graphics::TBitmap * bm70yellow
Definition: GraphicUnit.h:469
TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap
void GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2, int &PrefDirPos3)
Return up to 4 vector positions for a given HLoc & VLoc; unused values return -1.
Definition: TrackUnit.cpp:12014
TRailGraphics::sm110
Graphics::TBitmap * sm110
Definition: GraphicUnit.h:765
TRailGraphics::sm92
Graphics::TBitmap * sm92
Definition: GraphicUnit.h:866
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:11189
TAllRoutes::TRoute2MultiMapEntry
std::pair< THVPair, TRouteElementPair > TRoute2MultiMapEntry
Definition: TrackUnit.h:1532
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:85
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1584
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:108
TRailGraphics::sm69
Graphics::TBitmap * sm69
Definition: GraphicUnit.h:903
TRailGraphics::gl123
Graphics::TBitmap * gl123
Definition: GraphicUnit.h:587
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:11669
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:13208
TRailGraphics::gl48
Graphics::TBitmap * gl48
Definition: GraphicUnit.h:651
TOneRoute::ForceCancelRoute
void ForceCancelRoute(int Caller)
Cancel a route immediately if a train occupies it when travelling in the wrong direction (or occupies...
Definition: TrackUnit.cpp:15997
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3241
TTrackElement::PlotVariableTrackElement
void PlotVariableTrackElement(int Caller, TDisplay *Disp) const
Plot the element on the display 'variable' indicates that the element may be named and if so may be p...
Definition: TrackUnit.cpp:141
TOnePrefDir::StorePrefDirElement
void StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map.
Definition: TrackUnit.cpp:12077
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:10258
TTrack::ThisNamedLocationLongEnoughForSplit
bool ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos, int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
See above under 'OneNamedLocationLongEnoughForSplit'.
Definition: TrackUnit.cpp:9663
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1499
TRailGraphics::sm109
Graphics::TBitmap * sm109
Definition: GraphicUnit.h:763
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:818
TPrefDirElement::GetRouteGraphicPtr
Graphics::TBitmap * GetRouteGraphicPtr(bool AutoSigsFlag, bool ConsecSignalsRoute)
picks up the appropriate route graphic
Definition: TrackUnit.cpp:532
TRailGraphics::bm74yellow
Graphics::TBitmap * bm74yellow
Definition: GraphicUnit.h:495
TTrack::Tag78Array
int Tag78Array[25][3]
Definition: TrackUnit.h:496
TTrack::PlotGap
void PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a gap on screen - may be set or unset.
Definition: TrackUnit.cpp:5289
TPrefDirElement::GetDirectionPrefDirGraphicPtr
Graphics::TBitmap * GetDirectionPrefDirGraphicPtr() const
picks up the EntryDirectionGraphicPtr for preferred directions
Definition: TrackUnit.cpp:813
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:11489
Under
@ Under
Definition: TrackUnit.h:73
TRailGraphics::bm59
Graphics::TBitmap * bm59
Definition: GraphicUnit.h:449
TOneRoute::PointsToBeChanged
bool PointsToBeChanged(int Caller) const
Called by GetNextNonPreferredRouteElement and GetNextPreferredRouteElement to check whether or not an...
Definition: TrackUnit.cpp:15549
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:710
TRailGraphics::gl84
Graphics::TBitmap * gl84
Definition: GraphicUnit.h:695
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:538
TTrackElement::operator!=
bool operator!=(TTrackElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:131
TTrack::ResetConnClkCheckUnsetGapJumps
bool ResetConnClkCheckUnsetGapJumps(int Caller)
Sets all Conns and CLks to -1 except for gapjumps that match and are properly set,...
Definition: TrackUnit.cpp:2517
TOnePrefDir::GetModifiablePrefDirElementAt
TPrefDirElement & GetModifiablePrefDirElementAt(int Caller, int At)
Return a modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:10410
TOnePrefDir::SearchForPrefDir
bool SearchForPrefDir(int Caller, TTrackElement TrackElement, int XLinkPos, int RequiredPosition)
Try to find a selected element from a given start position. Enter with CurrentTrackElement stored in ...
Definition: TrackUnit.cpp:10732
TRailGraphics::sm96
Graphics::TBitmap * sm96
Definition: GraphicUnit.h:870
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:346
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:133
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:117
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:54
TTrack::OneNamedLocationLongEnoughForSplit
bool OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
Definition: TrackUnit.cpp:9566
Lead
@ Lead
Definition: TrackUnit.h:73
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5154
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1533
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:12323
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:775
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:527
TTrack::WriteTrackToImage
void WriteTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3449
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:217
TTrack::TrackPush
void TrackPush(int Caller, TTrackElement TrackElement)
Insert TrackElement into the relevant vector and map, and, if named, insert the name in LocationNameM...
Definition: TrackUnit.cpp:4986
TTrack::IsBarrierDownVectorAtHVManual
bool IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
True if there is a vector entry at H & V that is set to manual (ConsecSignals == 2) and returns the v...
Definition: TrackUnit.cpp:5746
TFixedTrackPiece::FixedNamedLocationElement
bool FixedNamedLocationElement
true for an element that can be named (platforms, concourse, footcrossings & non-station named loacti...
Definition: TrackUnit.h:83
TOnePrefDir::PrefDirSearchLimit
static const int PrefDirSearchLimit
limit to the number of elements searched in attempting to find a preferred direction
Definition: TrackUnit.h:1234
TTrack::GetTrackVectorIteratorFromNamePosition
TTrackVectorIterator GetTrackVectorIteratorFromNamePosition(int Caller, int Position)
Takes an adjusted vector position value from either vector (if active, Position = -TruePos -1,...
Definition: TrackUnit.cpp:8475
TRailGraphics::bm70grounddblwhite
Graphics::TBitmap * bm70grounddblwhite
Definition: GraphicUnit.h:467
TRailGraphics::bm70green
Graphics::TBitmap * bm70green
Definition: GraphicUnit.h:468
TRailGraphics::gl115
Graphics::TBitmap * gl115
Definition: GraphicUnit.h:578
TTrack::Up
@ Up
Definition: TrackUnit.h:523
TRailGraphics::sm89
Graphics::TBitmap * sm89
Definition: GraphicUnit.h:862
TTrack::NextTrackElementPtr
TTrackVectorIterator NextTrackElementPtr
track vector iterator used during cycling through a track vector
Definition: TrackUnit.h:712
TTrack::Tag130Array
int Tag130Array[8][3]
Definition: TrackUnit.h:500
TTrack::BlankElementAt
bool BlankElementAt(int Caller, int At) const
Definition: TrackUnit.cpp:9545
TRailGraphics::sm127
Graphics::TBitmap * sm127
Definition: GraphicUnit.h:922
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1371
TDisplay::PlotSignalBlankOnBitmap
void PlotSignalBlankOnBitmap(int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *Bitmap, bool RHSFlag)
Definition: DisplayUnit.cpp:339
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:7774
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1525
TTrack::LCFoundInAutoSigsRoute
bool LCFoundInAutoSigsRoute
true if found an LC during an automatic route search
Definition: TrackUnit.h:652
TPrefDirElement::XLink
int XLink
Definition: TrackUnit.h:215
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1515
TRailGraphics::bm133
Graphics::TBitmap * bm133
Definition: GraphicUnit.h:362
TRailGraphics::sm135
Graphics::TBitmap * sm135
Definition: GraphicUnit.h:780
Crossover
@ Crossover
Definition: TrackUnit.h:63
TTrack::SetLinkedManualLCs
void SetLinkedManualLCs(int Caller, int HLoc, int VLoc)
Set all ConsecSignals values to 2 for all linked LCs to indicate manually lowered.
Definition: TrackUnit.cpp:5633
TRailGraphics::bm71green
Graphics::TBitmap * bm71green
Definition: GraphicUnit.h:474
TRailGraphics::bm51
Graphics::TBitmap * bm51
Definition: GraphicUnit.h:445
TTrack::UGME
TUserGraphicMapEntry UGME
an entry for the UserGraphicMap
Definition: TrackUnit.h:714
TRailGraphics::gl21
Graphics::TBitmap * gl21
Definition: GraphicUnit.h:622
TTrack::ElementInLNDone2MultiMap
bool ElementInLNDone2MultiMap(int Caller, int MapPos)
True if the element defined by MapPos is present in LNDone2MultiMap, used during location naming.
Definition: TrackUnit.cpp:7720
TRailGraphics::sm137
Graphics::TBitmap * sm137
Definition: GraphicUnit.h:782
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:6622
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:9017
DefaultTrackLength
#define DefaultTrackLength
Definition: TrackUnit.h:37
TRailGraphics::bm68CallingOn
Graphics::TBitmap * bm68CallingOn
Definition: GraphicUnit.h:451
Signal
@ Signal
Definition: TrackUnit.h:73
TTrack::VLocMin
int VLocMin
Definition: TrackUnit.h:487
TTrack::LevelCrossingAllowed
Set< int, 1, 146 > LevelCrossingAllowed
sets of valid TrackElements for placement of platforms and non-station named locations
Definition: TrackUnit.h:505
TRailGraphics::bm69grounddblwhite
Graphics::TBitmap * bm69grounddblwhite
Definition: GraphicUnit.h:460
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:682
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:16506
TTrackElement::TrainIDOnBridgeTrackPos01
int TrainIDOnBridgeTrackPos01
Definition: TrackUnit.h:151
TTrack::TFixedTrackArray::TFixedTrackArray
TFixedTrackArray()
Array constructor.
Definition: TrackUnit.cpp:1261
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:11539
TRailGraphics::bm78Striped
Graphics::TBitmap * bm78Striped
Definition: GraphicUnit.h:505
TTrack::TrainOnLink
bool TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID)
New at v1.2.0; checks whether a train present at input location and link and returns its ID if so.
Definition: TrackUnit.cpp:10152
TTrack::ResetAnyNonMatchingGaps
void ResetAnyNonMatchingGaps(int Caller)
Called by EraseTrackElement after the element has been erased and the vector positions changed,...
Definition: TrackUnit.cpp:4173
TTrack::GapPos
int GapPos
Definition: TrackUnit.h:485
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackElement.at(At)
Definition: TrackUnit.cpp:9518
TGraphicElement::Width
int Width
Definition: TrackUnit.h:353
TAllRoutes::RouteLockingRequired
bool RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTru...
Definition: TrackUnit.cpp:17401
TRailGraphics::bmGreenEllipse
Graphics::TBitmap * bmGreenEllipse
Definition: GraphicUnit.h:519
TAllRoutes::GetRouteVectorNumber
int GetRouteVectorNumber(int Caller, IDInt RouteID)
Returns a route's position in AllRoutesVector from its ID, throws an error if a matching route isn't ...
Definition: TrackUnit.cpp:17598
TAllRoutes::GetRouteTypeAndGraphics
TRouteType GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap *&EXGraphicPtr, Graphics::TBitmap *&EntryDirectionGraphicPtr)
Examines Route2MultiMap for the element at TrackVectorPosition with LinkPos (can be entry or exit).
Definition: TrackUnit.cpp:16331
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:687
TRailGraphics::bm73green
Graphics::TBitmap * bm73green
Definition: GraphicUnit.h:487
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:731
TRailGraphics::gl107
Graphics::TBitmap * gl107
Definition: GraphicUnit.h:569
TRailGraphics::bm53
Graphics::TBitmap * bm53
Definition: GraphicUnit.h:446
TTrack::WriteOperatingTrackToImage
void WriteOperatingTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track element graphics to the image file in...
Definition: TrackUnit.cpp:3733
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or CR accepted as delimiters), returns true for success and re...
Definition: Utilities.cpp:468
TRailGraphics::sm12
Graphics::TBitmap * sm12
Definition: GraphicUnit.h:770
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:33
TTrack::TTrackMapIterator
TTrackMap::iterator TTrackMapIterator
Definition: TrackUnit.h:570
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:3711
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2058
TTrack::TLocationNameMultiMapIterator
TLocationNameMultiMap::iterator TLocationNameMultiMapIterator
Definition: TrackUnit.h:603
TRailGraphics::bm70CallingOn
Graphics::TBitmap * bm70CallingOn
Definition: GraphicUnit.h:464
TTrack::RebuildLocationNameMultiMap
void RebuildLocationNameMultiMap(int Caller)
Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector....
Definition: TrackUnit.cpp:8599
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green ...
Definition: TrackUnit.cpp:11320
TRailGraphics::gl124
Graphics::TBitmap * gl124
Definition: GraphicUnit.h:588
TRailGraphics::bm32
Graphics::TBitmap * bm32
Definition: GraphicUnit.h:406
TRailGraphics::sm88
Graphics::TBitmap * sm88
Definition: GraphicUnit.h:861
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:845
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5130
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:17681
TRailGraphics::gl105
Graphics::TBitmap * gl105
Definition: GraphicUnit.h:567
TOneRoute::StartElement1
TPrefDirElement StartElement1
Definition: TrackUnit.h:1413
TRailGraphics::sm75
Graphics::TBitmap * sm75
Definition: GraphicUnit.h:909
TRailGraphics::sm115
Graphics::TBitmap * sm115
Definition: GraphicUnit.h:768
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1402
TRailGraphics::sm53
Graphics::TBitmap * sm53
Definition: GraphicUnit.h:827
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement - always plots as red - auto.
Definition: TrackUnit.cpp:6331
TRailGraphics::bm71CallingOn
Graphics::TBitmap * bm71CallingOn
Definition: GraphicUnit.h:470
TTrack::LCFoundInRouteBuildingFlag
bool LCFoundInRouteBuildingFlag
true if a route set through an LC that is closed to trains (& therefore needs to be opened)
Definition: TrackUnit.h:656
TRailGraphics::DirectionSigRouteGraphicsPtr
Graphics::TBitmap * DirectionSigRouteGraphicsPtr[10]
preferred direction route marker arrows
Definition: GraphicUnit.h:1028
TRailGraphics::DirectionRouteAutoSigsGraphicsPtr
Graphics::TBitmap * DirectionRouteAutoSigsGraphicsPtr[10]
autosigs route marker arrows
Definition: GraphicUnit.h:1030
TRailGraphics::bm93set
Graphics::TBitmap * bm93set
Definition: GraphicUnit.h:513
TTrack::GetTrackVectorPositionFromString
int GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
Takes the ElementID value (an AnsiString) (e.g. "8-13", "N43-N127", etc) and returns the correspondin...
Definition: TrackUnit.cpp:7050
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:16151
TTrack::TTrackMapEntry
std::pair< THVPair, unsigned int > TTrackMapEntry
Definition: TrackUnit.h:571
TRailGraphics::bm37
Graphics::TBitmap * bm37
Definition: GraphicUnit.h:421
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:6695
TRailGraphics::sm139
Graphics::TBitmap * sm139
Definition: GraphicUnit.h:784
Erase
@ Erase
Definition: TrackUnit.h:64
TRailGraphics::sm57
Graphics::TBitmap * sm57
Definition: GraphicUnit.h:831
TRailGraphics::bm29
Graphics::TBitmap * bm29
Definition: GraphicUnit.h:397
TRailGraphics::bm72grounddblwhite
Graphics::TBitmap * bm72grounddblwhite
Definition: GraphicUnit.h:479
TTrack::IsTrackLinked
bool IsTrackLinked(int Caller)
True if track has been successfully linked (not used any more)
Definition: TrackUnit.cpp:4810
TTrack::NewVector
TTrackVector NewVector
Definition: TrackUnit.h:710
TAllRoutes::LockedRouteTruncateTrackVectorPosition
unsigned int LockedRouteTruncateTrackVectorPosition
Definition: TrackUnit.h:1564
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:123
TRailGraphics::sm39
Graphics::TBitmap * sm39
Definition: GraphicUnit.h:811
TRailGraphics::sm85
Graphics::TBitmap * sm85
Definition: GraphicUnit.h:858
TRailGraphics::gl112
Graphics::TBitmap * gl112
Definition: GraphicUnit.h:575
TOnePrefDir::GetExactMatchFrom4MultiMap
TPrefDir4MultiMapIterator GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition....
Definition: TrackUnit.cpp:12145
TTrack::GetAnyElementOppositeLinkPos
int GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
Return the opposite link position for the element at TrackVectorPosition with link position LinkPos,...
Definition: TrackUnit.cpp:10065
Parapet
@ Parapet
Definition: TrackUnit.h:64
TRailGraphics::bm54
Graphics::TBitmap * bm54
Definition: GraphicUnit.h:447
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:16176
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:65
TRailGraphics::sm14
Graphics::TBitmap * sm14
Definition: GraphicUnit.h:785
TRailGraphics::bmStraightEWSignalBlank
Graphics::TBitmap * bmStraightEWSignalBlank
Definition: GraphicUnit.h:992
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:277
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:8284
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:16126
TRailGraphics::bm138
Graphics::TBitmap * bm138
Definition: GraphicUnit.h:377
TRailGraphics::sm79striped
Graphics::TBitmap * sm79striped
Definition: GraphicUnit.h:851
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:710
TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap
void DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap,...
Definition: TrackUnit.cpp:17043
TRailGraphics::gl126
Graphics::TBitmap * gl126
Definition: GraphicUnit.h:590
TRailGraphics::sm119
Graphics::TBitmap * sm119
Definition: GraphicUnit.h:914
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
map of active track element names
Definition: TrackUnit.h:685
TRailGraphics::sm138
Graphics::TBitmap * sm138
Definition: GraphicUnit.h:783
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:145
TRailGraphics::bm72grounddblred
Graphics::TBitmap * bm72grounddblred
Definition: GraphicUnit.h:478
TRailGraphics::sm34
Graphics::TBitmap * sm34
Definition: GraphicUnit.h:806
TDisplay::PlotPointBlank
void PlotPointBlank(int Caller, int HLoc, int VLoc)
Definition: DisplayUnit.cpp:241
TRailGraphics::ConcourseStriped
Graphics::TBitmap * ConcourseStriped
Definition: GraphicUnit.h:549
TRailGraphics::PointModeGraphicsPtr
Graphics::TBitmap * PointModeGraphicsPtr[32][2]
for point fillets - 32 sets of points, each with two fillets
Definition: GraphicUnit.h:1033
TTrack::SigTableTwoAspect
TSigElement SigTableTwoAspect[40]
new at version 0.6 for two aspect
Definition: TrackUnit.h:635
TRailGraphics::sm27
Graphics::TBitmap * sm27
Definition: GraphicUnit.h:798
TTrainController::LogActionError
void LogActionError(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionEventType ActionEventType, AnsiString LocationID)
Send an error message to the performance log and file, and as a warning if appropriate.
Definition: TrainUnit.cpp:13645
TRailGraphics::sm5
Graphics::TBitmap * sm5
Definition: GraphicUnit.h:823
TTrackElement::LCPlotted
bool LCPlotted
Utility marker to avoid plotting every element of a multitrack LC during ClearandRebuildRailway.
Definition: TrackUnit.h:135
TPrefDirElement::EXNumber
int EXNumber
used to facilitate identification of the appropriate preferred direction or route graphic
Definition: TrackUnit.h:217
TTrack::NumberOfPlatforms
int NumberOfPlatforms(int Caller, AnsiString LocationName)
Returns the number of separate platforms (not platform elements) at a given location,...
Definition: TrackUnit.cpp:10286
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track marker, including direction markers.
Definition: TrackUnit.cpp:11247
TRailGraphics::bm78
Graphics::TBitmap * bm78
Definition: GraphicUnit.h:504
TTruncateReturnType
TTruncateReturnType
< a flag used during route truncation to indicate the nature of the selected element,...
Definition: TrackUnit.h:1179
TRailGraphics::bm75CallingOn
Graphics::TBitmap * bm75CallingOn
Definition: GraphicUnit.h:496
TRailGraphics::gl130
Graphics::TBitmap * gl130
Definition: GraphicUnit.h:596
TRailGraphics::bm71yellow
Graphics::TBitmap * bm71yellow
Definition: GraphicUnit.h:475
TRailGraphics::LCRHSVerMan
Graphics::TBitmap * LCRHSVerMan
Definition: GraphicUnit.h:731
TTrack
Definition: TrackUnit.h:463
TOnePrefDir::SearchLimitHighH
int SearchLimitHighH
Definition: TrackUnit.h:1242
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:757
TOnePrefDir::PrefDirVector
TPrefDirVector PrefDirVector
Definition: TrackUnit.h:1249
TAllRoutes::SetTrailingSignalsOnAutoSigsRoute
void SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
Enter with signal at TrackVectorElement already set to red by the passing train.
Definition: TrackUnit.cpp:17191
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:286
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TAllRoutes::TLockedRouteClass::RouteNumber
int RouteNumber
the vector position number of the relevant route in AllRoutesVector
Definition: TrackUnit.h:1502
TTrack::ActiveMapCheck
bool ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:7325
TRailGraphics::gl2
Graphics::TBitmap * gl2
Definition: GraphicUnit.h:620
TTrack::Tag146Array
int Tag146Array[8][3]
Definition: TrackUnit.h:503
TRailGraphics::sm65
Graphics::TBitmap * sm65
Definition: GraphicUnit.h:840
TRailGraphics::gl47
Graphics::TBitmap * gl47
Definition: GraphicUnit.h:650
TRailGraphics::LCBothHorMan
Graphics::TBitmap * LCBothHorMan
Definition: GraphicUnit.h:726
TRailGraphics::sm78striped
Graphics::TBitmap * sm78striped
Definition: GraphicUnit.h:849
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:126
TRailGraphics::sm33
Graphics::TBitmap * sm33
Definition: GraphicUnit.h:805
TRailGraphics::bm94set
Graphics::TBitmap * bm94set
Definition: GraphicUnit.h:515
TRailGraphics::gl76Striped
Graphics::TBitmap * gl76Striped
Definition: GraphicUnit.h:685
TPrefDirElement::XLinkPos
int XLinkPos
exit link number & array position
Definition: TrackUnit.h:215
TAllRoutes::StoreOneRouteAfterSessionLoad
void StoreOneRouteAfterSessionLoad(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load....
Definition: TrackUnit.cpp:16682
TPrefDirElement::EntryDirectionGraphicPtr
Graphics::TBitmap * EntryDirectionGraphicPtr
pointers to the appropriate entry/exit graphic, or direction marker graphic, for preferred directions...
Definition: TrackUnit.h:223
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:2596
TRailGraphics::bm65
Graphics::TBitmap * bm65
Definition: GraphicUnit.h:450
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:7969
TRailGraphics::sm74
Graphics::TBitmap * sm74
Definition: GraphicUnit.h:908
TTrack::PlotSignalPlatforms
void PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
Plot platforms if any for a signal graphic - plotted before signal so shows through transparent signa...
Definition: TrackUnit.cpp:5527
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:1823
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:131
TTrack::Tag145Array
int Tag145Array[8][3]
Definition: TrackUnit.h:502
TRailGraphics::LCRHSVer
Graphics::TBitmap * LCRHSVer
Definition: GraphicUnit.h:724
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:156
TRailGraphics::sm76
Graphics::TBitmap * sm76
Definition: GraphicUnit.h:844
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:693
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2281
TPrefDirElement::ELinkPos
int ELinkPos
entry link number & array position
Definition: TrackUnit.h:213
TAllRoutes::TLockedRouteClass
Handles routes that are locked because of approaching trains.
Definition: TrackUnit.h:1500
TTrack::SetElementID
void SetElementID(int Caller, TTrackElement &TrackElement)
Convert the position values for the TrackElement into an identification string and load in ElementID.
Definition: TrackUnit.cpp:7022
TRailGraphics::bm72yellow
Graphics::TBitmap * bm72yellow
Definition: GraphicUnit.h:481
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:11035
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:11792
TTrack::Tag131Array
int Tag131Array[4][3]
Definition: TrackUnit.h:501
TOneRoute::TRouteFlashElement::TrackVectorPosition
int TrackVectorPosition
element values
Definition: TrackUnit.h:1377
TTrack::RetrieveStripedNamedLocationGraphicsWhereRelevant
Graphics::TBitmap * RetrieveStripedNamedLocationGraphicsWhereRelevant(int Caller, TTrackElement TrackElement)
Return a pointer to the striped (i.e. when unnamed) graphic corresponding to TrackElement,...
Definition: TrackUnit.cpp:9455
TTrack::AddName
void AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
TrackElement.LocationName becomes 'Name' (for active and inactive elements) and, if TrackElement is a...
Definition: TrackUnit.cpp:7683
IDInt
Definition: TrackUnit.h:412
TTrain::GetLeadElement
void GetLeadElement(int Caller)
Called when a train is about to leave an element and move onto another.
Definition: TrainUnit.cpp:2281
TRailGraphics::gl110
Graphics::TBitmap * gl110
Definition: GraphicUnit.h:573
TAllRoutes::GetModifiableRouteAtIDNumber
TOneRoute & GetModifiableRouteAtIDNumber(int Caller, IDInt RouteID)
Returns a modifiable reference to the route with ID number RouteID. If no route is found with that ID...
Definition: TrackUnit.cpp:17649
TRailGraphics::gl130Striped
Graphics::TBitmap * gl130Striped
Definition: GraphicUnit.h:597
TRailGraphics::sm133
Graphics::TBitmap * sm133
Definition: GraphicUnit.h:778
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:3980
TDisplay
Definition: DisplayUnit.h:48
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:9265
TTrack::LinkTrackNoMessages
bool LinkTrackNoMessages(int Caller, bool FinalCall)
Attempt to link the track and return true if successful, don't issue any screen messages....
Definition: TrackUnit.cpp:4585
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:143
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:797
TRailGraphics::sm129striped
Graphics::TBitmap * sm129striped
Definition: GraphicUnit.h:772
TRailGraphics::sm48
Graphics::TBitmap * sm48
Definition: GraphicUnit.h:821
TGraphicElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
original and temporary overlay graphics
Definition: TrackUnit.h:355
TAllRoutes::CheckForLoopingRoute
bool CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
Functions defined in .cpp file.
Definition: TrackUnit.cpp:17746
TTrack::TTrack
TTrack()
Constructor, only one object of this class.
Definition: TrackUnit.cpp:894
TTrack::FindNamedElementInLocationNameMultiMap
TLocationNameMultiMapIterator FindNamedElementInLocationNameMultiMap(int Caller, AnsiString LocationName, TTrackVectorIterator TrackElement, AnsiString &ErrorString)
Searches LocationNameMultiMap to check if the element pointed to by the TTrackVectorIterator has the ...
Definition: TrackUnit.cpp:8400
TTrackElement::operator==
bool operator==(TTrackElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:121
TTrack::GapHLoc
int GapHLoc
Definition: TrackUnit.h:485
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:95
TTrack::CheckGapMap
void CheckGapMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:6971
NotInRoute
@ NotInRoute
Definition: TrackUnit.h:1180
TDisplay::GetRectangle
void GetRectangle(int Caller, TRect DestRect, TRect SourceRect, Graphics::TBitmap *&OriginalGraphic)
Definition: DisplayUnit.cpp:221
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:151
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:885
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:671
TRailGraphics::LCPlainMan
Graphics::TBitmap * LCPlainMan
Definition: GraphicUnit.h:730
TRailGraphics::bm139
Graphics::TBitmap * bm139
Definition: GraphicUnit.h:380
TRailGraphics::gl3
Graphics::TBitmap * gl3
Definition: GraphicUnit.h:631
TPrefDirElement::CheckCount
int CheckCount
internal check value used when building preferred directions
Definition: TrackUnit.h:221
TRailGraphics::bm20
Graphics::TBitmap * bm20
Definition: GraphicUnit.h:392
TRailGraphics::sm77striped
Graphics::TBitmap * sm77striped
Definition: GraphicUnit.h:847
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1569
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:154
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:128
TRailGraphics::sm112
Graphics::TBitmap * sm112
Definition: GraphicUnit.h:767
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:6939
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:544
TRailGraphics::sm36
Graphics::TBitmap * sm36
Definition: GraphicUnit.h:808
TRailGraphics::sm136
Graphics::TBitmap * sm136
Definition: GraphicUnit.h:781
TRailGraphics::gl98
Graphics::TBitmap * gl98
Definition: GraphicUnit.h:715
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:145
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:791
TRailGraphics::sm100
Graphics::TBitmap * sm100
Definition: GraphicUnit.h:754
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1388
TRailGraphics::sm63
Graphics::TBitmap * sm63
Definition: GraphicUnit.h:838
TAllRoutes::TLockedRouteClass::LastTrackVectorPosition
unsigned int LastTrackVectorPosition
the TrackVector position of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1506
TRailGraphics::sm60
Graphics::TBitmap * sm60
Definition: GraphicUnit.h:835
TAllRoutes::NoRoute
@ NoRoute
Definition: TrackUnit.h:1516
TRailGraphics::bm42
Graphics::TBitmap * bm42
Definition: GraphicUnit.h:436
TTrack::RepositionAndMapTrack
bool RepositionAndMapTrack(int Caller)
When track is being built it is entered into the TrackVector in the order in which it is built,...
Definition: TrackUnit.cpp:4244
TRailGraphics::gl108
Graphics::TBitmap * gl108
Definition: GraphicUnit.h:570
TTrack::AdjNamedElement
bool AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
Definition: TrackUnit.cpp:8223
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:644
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:14147
TOnePrefDir::ClearPrefDir
void ClearPrefDir()
Empty the existing vectors & map.
Definition: TrackUnit.h:1207
TRailGraphics::gl99
Graphics::TBitmap * gl99
Definition: GraphicUnit.h:716
TGraphicElement::OverlayLoaded
bool OverlayLoaded
Definition: TrackUnit.h:349
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:12251
TRailGraphics::sm4
Graphics::TBitmap * sm4
Definition: GraphicUnit.h:812
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1186
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:149
Points
@ Points
Definition: TrackUnit.h:63
TRailGraphics::gl89unset
Graphics::TBitmap * gl89unset
Definition: GraphicUnit.h:702
TOneRoute::SearchForPreferredRoute
bool SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, int EndSelectPosition, bool AutoSigsFlag)
Called by GetNextPreferredRouteElement to carry out the search for a valid route, and also called rec...
Definition: TrackUnit.cpp:13662
TRailGraphics::LCPlain
Graphics::TBitmap * LCPlain
Definition: GraphicUnit.h:723
TAllRoutes::FindRoutePairFromRoute2MultiMap
TRouteElementPair FindRoutePairFromRoute2MultiMap(int Caller, int HLoc, int VLoc, int ELink, TRoute2MultiMapIterator &Route2MultiMapIterator)
Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H,...
Definition: TrackUnit.cpp:16756
TRailGraphics::sm80
Graphics::TBitmap * sm80
Definition: GraphicUnit.h:853
TTrack::IsElementDefaultLength
bool IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
Definition: TrackUnit.cpp:8948
TTrack::PopulateLCVector
void PopulateLCVector(int Caller)
Add all LCs to LCVector - note that this contains all LC elements whether linked to others or not.
Definition: TrackUnit.cpp:10135
TRailGraphics::bm33
Graphics::TBitmap * bm33
Definition: GraphicUnit.h:409
TRailGraphics::gl119
Graphics::TBitmap * gl119
Definition: GraphicUnit.h:582
TRailGraphics::sm47
Graphics::TBitmap * sm47
Definition: GraphicUnit.h:820
TRailGraphics::bm75grounddblred
Graphics::TBitmap * bm75grounddblred
Definition: GraphicUnit.h:498
Trail
@ Trail
Definition: TrackUnit.h:73
TTrack::ChangeLocationNameMultiMapEntry
void ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationN...
Definition: TrackUnit.cpp:8457
TOneRoute::SetRearwardsSignalsReturnFalseForTrain
bool SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
Called by TAllRoutes::SetAllRearwardsSignals to set rearwards signals from a specified starting posit...
Definition: TrackUnit.cpp:15661
TRailGraphics::sm107
Graphics::TBitmap * sm107
Definition: GraphicUnit.h:761
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1569
TRailGraphics::bm75dblyellow
Graphics::TBitmap * bm75dblyellow
Definition: GraphicUnit.h:497
FailLockedRoute
@ FailLockedRoute
Definition: TrainUnit.h:40
TRailGraphics::sm32
Graphics::TBitmap * sm32
Definition: GraphicUnit.h:804
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all points appropriately. Also called when a new train is added at...
Definition: TrackUnit.cpp:15486
TRailGraphics::sm44
Graphics::TBitmap * sm44
Definition: GraphicUnit.h:817
TRailGraphics::gl44
Graphics::TBitmap * gl44
Definition: GraphicUnit.h:647
TRailGraphics::bm36
Graphics::TBitmap * bm36
Definition: GraphicUnit.h:418
TRailGraphics::LCTopHor
Graphics::TBitmap * LCTopHor
Definition: GraphicUnit.h:725
Continuation
@ Continuation
Definition: TrackUnit.h:63
TRailGraphics::DirectionPrefDirGraphicsPtr
Graphics::TBitmap * DirectionPrefDirGraphicsPtr[10]
preferred direction marker arrows
Definition: GraphicUnit.h:1024
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:35
TTrack::GetFilletGraphic
Graphics::TBitmap * GetFilletGraphic(int Caller, TTrackElement TrackElement)
Return a pointer to the point fillet (the bit that appears to move when points are changed) for the p...
Definition: TrackUnit.cpp:6818
GraphicUnit.h
THVPair
std::pair< int, int > THVPair
HLoc/VLoc position pair.
Definition: InterfaceUnit.h:47
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3341
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:5366
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:86
TTrack::RightPlatAllowed
Set< int, 1, 146 > RightPlatAllowed
Definition: TrackUnit.h:505
TRailGraphics::bm12
Graphics::TBitmap * bm12
Definition: GraphicUnit.h:355
TTrack::DecrementValuesInInactiveTrackAndNameMaps
void DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the InactiveTrackVector, all the later elements are moved down ...
Definition: TrackUnit.cpp:8504
TRailGraphics::sm8
Graphics::TBitmap * sm8
Definition: GraphicUnit.h:852
TRailGraphics::sm87
Graphics::TBitmap * sm87
Definition: GraphicUnit.h:860
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TRailGraphics::sm94
Graphics::TBitmap * sm94
Definition: GraphicUnit.h:868
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:11078
TTrack::LinkHVArray
int LinkHVArray[10][2]
array used to determine relative horizontal & vertical track element positions for specific link valu...
Definition: TrackUnit.h:491
TRailGraphics::sm49
Graphics::TBitmap * sm49
Definition: GraphicUnit.h:822
TRailGraphics::sm1
Graphics::TBitmap * sm1
Definition: GraphicUnit.h:752
TRailGraphics::sm84
Graphics::TBitmap * sm84
Definition: GraphicUnit.h:857
TGraphicElement::ScreenGraphicLoaded
bool ScreenGraphicLoaded
Definition: TrackUnit.h:349
TTrack::TopPlatAllowed
Set< int, 1, 146 > TopPlatAllowed
Definition: TrackUnit.h:505
TRailGraphics::LinkPrefDirGraphicsPtr
Graphics::TBitmap * LinkPrefDirGraphicsPtr[30]
preferred direction graphic overlay
Definition: GraphicUnit.h:1013
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:2958
TGraphicElement::Height
int Height
dimensions in pixels
Definition: TrackUnit.h:353
TRailGraphics::sm98
Graphics::TBitmap * sm98
Definition: GraphicUnit.h:873
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1405
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:85
TRailGraphics::bm68green
Graphics::TBitmap * bm68green
Definition: GraphicUnit.h:455
TRailGraphics::gl79
Graphics::TBitmap * gl79
Definition: GraphicUnit.h:688
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:614
TTrack::SigTableGroundSignal
TSigElement SigTableGroundSignal[40]
new at version 0.6 for ground signals
Definition: TrackUnit.h:637
TAllRoutes::LockedRouteLastXLinkPos
int LockedRouteLastXLinkPos
Definition: TrackUnit.h:1563
TRailGraphics::sm113
Graphics::TBitmap * sm113
Definition: GraphicUnit.h:910
TRailGraphics::bm135
Graphics::TBitmap * bm135
Definition: GraphicUnit.h:368
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:271
TRailGraphics::LCBothVerMan
Graphics::TBitmap * LCBothVerMan
Definition: GraphicUnit.h:728
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:294
TRailGraphics::sm61
Graphics::TBitmap * sm61
Definition: GraphicUnit.h:836
TAllRoutes::DiagonalFouledByRouteOrTrain
bool DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
The track geometry allows diagonals to cross without occupying the same track element,...
Definition: TrackUnit.cpp:17819
TRailGraphics::bm73grounddblwhite
Graphics::TBitmap * bm73grounddblwhite
Definition: GraphicUnit.h:486
TOnePrefDir::CheckPrefDir4MultiMap
void CheckPrefDir4MultiMap(int Caller)
Diagnostic validity check.
Definition: TrackUnit.cpp:11978
TRailGraphics::BridgeSigRouteGraphicsPtr
Graphics::TBitmap * BridgeSigRouteGraphicsPtr[12]
route graphic for preferred routes overlay
Definition: GraphicUnit.h:1002
TRailGraphics::bm73dblyellow
Graphics::TBitmap * bm73dblyellow
Definition: GraphicUnit.h:484
TRailGraphics::sm111
Graphics::TBitmap * sm111
Definition: GraphicUnit.h:766
TOneRoute::TRouteFlashElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:1379
TRailGraphics::BridgeRouteAutoSigsGraphicsPtr
Graphics::TBitmap * BridgeRouteAutoSigsGraphicsPtr[12]
route graphic for automatic signal routes overlay
Definition: GraphicUnit.h:1006
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:84
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:53
TRailGraphics::bm106
Graphics::TBitmap * bm106
Definition: GraphicUnit.h:349
TRailGraphics::bm56
Graphics::TBitmap * bm56
Definition: GraphicUnit.h:448
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:677
TRailGraphics::gl146Striped
Graphics::TBitmap * gl146Striped
Definition: GraphicUnit.h:615
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:785
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0)
Definition: TrackUnit.cpp:4229
TRailGraphics::sm96striped
Graphics::TBitmap * sm96striped
Definition: GraphicUnit.h:871
TAllRoutes::StoreOneRoute
void StoreOneRoute(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector.
Definition: TrackUnit.cpp:16653
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1596
TTrack::DuplicatedLocationName
bool DuplicatedLocationName(int Caller, bool GiveMessage)
examines LocationNameMultiMap and returns true if there are two or more locations with the same name ...
Definition: TrackUnit.cpp:7821
TRailGraphics::gl87
Graphics::TBitmap * gl87
Definition: GraphicUnit.h:698
TTrack::THVPairsLinkedMap
std::map< THVPair, bool > THVPairsLinkedMap
added at v2.6.1 for use in PopulateHVPairsLinkedMapAndNoDuplicates
Definition: TrackUnit.h:607
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:121
TRailGraphics::gl113
Graphics::TBitmap * gl113
Definition: GraphicUnit.h:576
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:697
TRailGraphics::gl49
Graphics::TBitmap * gl49
Definition: GraphicUnit.h:652
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:198
TTrack::OtherTrainOnTrack
bool OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
True if another train on NextEntryPos track of element at NextPos, whether bridge or not,...
Definition: TrackUnit.cpp:9929
TRailGraphics::sm38
Graphics::TBitmap * sm38
Definition: GraphicUnit.h:810
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:618
TOnePrefDir::SearchLimitHighV
int SearchLimitHighV
Definition: TrackUnit.h:1244
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:17665
TTrack::Tag77Array
int Tag77Array[25][3]
Definition: TrackUnit.h:495
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1579
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0)
Definition: TrackUnit.cpp:4214
Connection
@ Connection
Definition: TrackUnit.h:73
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3318
TPrefDirElement::ConsecSignals
bool ConsecSignals
marker within the route for ConsecSignalsRoute element
Definition: TrackUnit.h:256
TRailGraphics::bm13
Graphics::TBitmap * bm13
Definition: GraphicUnit.h:358
TAllRoutes::RouteTruncateFlag
bool RouteTruncateFlag
used to flag the fact that a route is being truncated on order to change the behaviour of signal aspe...
Definition: TrackUnit.h:1571
TTrack::MarkOneLength
void MarkOneLength(int Caller, TTrackElement TE, bool FirstTrack, TDisplay *Disp)
Mark on screen a track element according to its length and speed limit if either of these differ from...
Definition: TrackUnit.cpp:8716
TRailGraphics::bmStraightNSSignalBlank
Graphics::TBitmap * bmStraightNSSignalBlank
Definition: GraphicUnit.h:993
TRailGraphics::LCTopHorMan
Graphics::TBitmap * LCTopHorMan
Definition: GraphicUnit.h:732
TRailGraphics::bm75green
Graphics::TBitmap * bm75green
Definition: GraphicUnit.h:500
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:15296
TOnePrefDir::ConvertPrefDirSearchVector
void ConvertPrefDirSearchVector(int Caller)
Called after a successful search to add the elements from the search vector to the pref dir vector.
Definition: TrackUnit.cpp:10909
TRailGraphics::gl91set
Graphics::TBitmap * gl91set
Definition: GraphicUnit.h:706
TRailGraphics::sm37
Graphics::TBitmap * sm37
Definition: GraphicUnit.h:809
TTrack::ElementInLNPendingList
bool ElementInLNPendingList(int Caller, int MapPos)
Definition: TrackUnit.cpp:7747
TRailGraphics::sm86
Graphics::TBitmap * sm86
Definition: GraphicUnit.h:859
TRailGraphics::LinkGraphicsPtr
Graphics::TBitmap * LinkGraphicsPtr[30]
basic single track graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1011
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:16967
TAllRoutes::GetRouteElementDataFromRoute2MultiMap
TRouteElementPair GetRouteElementDataFromRoute2MultiMap(int Caller, int HLoc, int VLoc, TRouteElementPair &SecondPair)
Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function re...
Definition: TrackUnit.cpp:16923
DefaultTrackSpeedLimit
#define DefaultTrackSpeedLimit
Definition: TrackUnit.h:38
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:6404
TPrefDirElement::GetPrefDirGraphicPtr
Graphics::TBitmap * GetPrefDirGraphicPtr()
picks up the EXGraphicPtr for preferred directions
Definition: TrackUnit.cpp:460
TTrack::PlatformOnSignalSide
bool PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *&SignalPlatformGraphic)
Check whether there is a platform present at HLoc & VLoc at the same side as the signal represented b...
Definition: TrackUnit.cpp:9816
TRailGraphics::gl80
Graphics::TBitmap * gl80
Definition: GraphicUnit.h:691
TRailGraphics::sm79
Graphics::TBitmap * sm79
Definition: GraphicUnit.h:850
TTrack::SigTable
TSigElement SigTable[40]
original table of signals for four aspect
Definition: TrackUnit.h:631
TOnePrefDir::TPrefDirVectorConstIterator
std::vector< TPrefDirElement >::const_iterator TPrefDirVectorConstIterator
Definition: TrackUnit.h:1232
TRailGraphics::smName
Graphics::TBitmap * smName
Definition: GraphicUnit.h:882
TRailGraphics::bm73grounddblred
Graphics::TBitmap * bm73grounddblred
Definition: GraphicUnit.h:485
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5174
TRailGraphics::sm7
Graphics::TBitmap * sm7
Definition: GraphicUnit.h:843
TRailGraphics::gl91unset
Graphics::TBitmap * gl91unset
Definition: GraphicUnit.h:707
TRailGraphics::bm50
Graphics::TBitmap * bm50
Definition: GraphicUnit.h:444
TDisplay::PlotSignalBlank
void PlotSignalBlank(int Caller, int HLoc, int VLoc, int SpeedTag, bool RHSFlag)
Definition: DisplayUnit.cpp:254
TGraphicElement::OriginalLoaded
bool OriginalLoaded
Definition: TrackUnit.h:349
TTrack::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
if false signals facing bridges are not permitted, but can be set to true using CTRL ALT 5
Definition: TrackUnit.h:664
TTrack::SetStationEntryStopLinkPosses
void SetStationEntryStopLinkPosses(int Caller)
Called when trying to link track and when a name changed when track already linked.
Definition: TrackUnit.cpp:9071
TTrack::HLocMin
int HLocMin
Definition: TrackUnit.h:487
TTrack::SigTableThreeAspect
TSigElement SigTableThreeAspect[40]
new at version 0.6 for three aspect
Definition: TrackUnit.h:633
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:644
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:16190
TTrack::LinkTrack
bool LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
Attempt to link the track and return true if successful, if unsuccessful return error flag and positi...
Definition: TrackUnit.cpp:4354
TRailGraphics::sm16
Graphics::TBitmap * sm16
Definition: GraphicUnit.h:787
TTrack::ErrorInTrackBeforeSetGaps
bool ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
Check for track errors prior to gap setting - disused as incorporated a time-consuming double brute f...
Definition: TrackUnit.cpp:2384
TRailGraphics::gl69
Graphics::TBitmap * gl69
Definition: GraphicUnit.h:674
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:6899
TRailGraphics::bm140
Graphics::TBitmap * bm140
Definition: GraphicUnit.h:386
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:2724
TRailGraphics::bm137
Graphics::TBitmap * bm137
Definition: GraphicUnit.h:374
TRailGraphics::sm64
Graphics::TBitmap * sm64
Definition: GraphicUnit.h:839
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:130
TRailGraphics::sm90
Graphics::TBitmap * sm90
Definition: GraphicUnit.h:864
TRailGraphics::bm136
Graphics::TBitmap * bm136
Definition: GraphicUnit.h:371
TOneRoute::SetRoutePoints
void SetRoutePoints(int Caller) const
Called when setting a route to set all points appropriately.
Definition: TrackUnit.cpp:15457
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:540
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:76
TOnePrefDir::PresetAutoRouteElementValid
bool PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos)
Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entr...
Definition: TrackUnit.cpp:12503
TPrefDirElement::EntryExitNumber
bool EntryExitNumber()
determines and loads EXNumber (see above)
Definition: TrackUnit.cpp:265
TRailGraphics::bm101
Graphics::TBitmap * bm101
Definition: GraphicUnit.h:348
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:662
TRailGraphics::gl125
Graphics::TBitmap * gl125
Definition: GraphicUnit.h:589
TTrack::TLocationNameMultiMapRange
std::pair< TLocationNameMultiMapIterator, TLocationNameMultiMapIterator > TLocationNameMultiMapRange
Definition: TrackUnit.h:604
TRailGraphics::gl145Striped
Graphics::TBitmap * gl145Striped
Definition: GraphicUnit.h:613
TRailGraphics::bm27
Graphics::TBitmap * bm27
Definition: GraphicUnit.h:393
TRailGraphics::bm73yellow
Graphics::TBitmap * bm73yellow
Definition: GraphicUnit.h:488
InRouteTrue
@ InRouteTrue
Definition: TrackUnit.h:1180
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:565
TRailGraphics::bm69yellow
Graphics::TBitmap * bm69yellow
Definition: GraphicUnit.h:462
TTrack::TGapMapIterator
TGapMap::iterator TGapMapIterator
the first gap HLoc/VLoc pair, contains one entry for each pair of matched gaps
Definition: TrackUnit.h:575
TRailGraphics::bmTransparentBgnd
Graphics::TBitmap * bmTransparentBgnd
Definition: GraphicUnit.h:898
TRailGraphics::gl23
Graphics::TBitmap * gl23
Definition: GraphicUnit.h:624
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:10489
TRailGraphics::bm68grounddblwhite
Graphics::TBitmap * bm68grounddblwhite
Definition: GraphicUnit.h:454
TGraphicElement::OverlayPlotted
bool OverlayPlotted
Definition: TrackUnit.h:349
TRailGraphics::bm93unset
Graphics::TBitmap * bm93unset
Definition: GraphicUnit.h:514
TRailGraphics::sm122
Graphics::TBitmap * sm122
Definition: GraphicUnit.h:917
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:98
TPrefDirElement::GetDirectionRouteGraphicPtr
Graphics::TBitmap * GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool ConsecSignalsRoute) const
picks up the green or red route direction graphic
Definition: TrackUnit.cpp:828
TOneRoute::TRouteFlashElement
A single flashing element of a route that flashes during setting.
Definition: TrackUnit.h:1375
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:210
TTrack::PopulateHVPairsLinkedMapAndNoDuplicates
bool PopulateHVPairsLinkedMapAndNoDuplicates(int Caller, TLocationNameMultiMapRange LNMMRg)
Used in checking for duplicate location names after Bill78 (discord name) developed the ....
Definition: TrackUnit.cpp:7864
TRailGraphics::sm26
Graphics::TBitmap * sm26
Definition: GraphicUnit.h:797
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int ConsecSignals, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:6478
TGraphicElement::~TGraphicElement
~TGraphicElement()
Destructor.
Definition: TrackUnit.cpp:1477
TTrack::SearchForAndUpdateLocationName
void SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
Checks all locations that are adjacent to the one entered for linked named location elements.
Definition: TrackUnit.cpp:8043
TRailGraphics::gl24
Graphics::TBitmap * gl24
Definition: GraphicUnit.h:625
TRailGraphics::gl109
Graphics::TBitmap * gl109
Definition: GraphicUnit.h:571
TTrack::TSigElement
Used as basic elements in a table of signals - see SigTable below.
Definition: TrackUnit.h:622
TOnePrefDir::GetOnePrefDirPosition
int GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
Although there may be up to four entries at one H & V position this function gets just one....
Definition: TrackUnit.cpp:12222
TAllRoutes::GetFixedRouteAtIDNumber
const TOneRoute & GetFixedRouteAtIDNumber(int Caller, IDInt RouteID) const
Returns a constant reference to the route with ID number RouteID. If no route is found with that ID a...
Definition: TrackUnit.cpp:17633
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise; points 0=set to ...
Definition: TrackUnit.h:139
TTrack::TBarrierState
TBarrierState
< state of barriers
Definition: TrackUnit.h:522
TOnePrefDir::SearchLimitLowH
int SearchLimitLowH
Definition: TrackUnit.h:1241
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4136
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:703
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4106
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:1670
TRailGraphics::bmRedEllipse
Graphics::TBitmap * bmRedEllipse
Definition: GraphicUnit.h:525
TRailGraphics::LinkRouteAutoSigsGraphicsPtr
Graphics::TBitmap * LinkRouteAutoSigsGraphicsPtr[30]
auto signal route graphic overlay
Definition: GraphicUnit.h:1019
TTrack::SetBarriersDownLCToManual
void SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
Set ConsecSignals value to 2 to indicate barriers manually closed.
Definition: TrackUnit.cpp:5673
TRailGraphics::bmDiagonalSignalBlank
Graphics::TBitmap * bmDiagonalSignalBlank
Definition: GraphicUnit.h:990
TRailGraphics::gl83
Graphics::TBitmap * gl83
Definition: GraphicUnit.h:694
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:63
TRailGraphics::sm50
Graphics::TBitmap * sm50
Definition: GraphicUnit.h:824
TRailGraphics::gl25
Graphics::TBitmap * gl25
Definition: GraphicUnit.h:626
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:6650
Platform
@ Platform
Definition: TrackUnit.h:63
TOnePrefDir::SearchVector
TPrefDirVector SearchVector
pref dir vectors, first is the main vector, second used to store search elements temporarily
Definition: TrackUnit.h:1249
TPrefDirElement::EXGraphicPtr
Graphics::TBitmap * EXGraphicPtr
Definition: TrackUnit.h:223
TTrack::TGapMapEntry
std::pair< THVPair, THVPair > TGapMapEntry
Definition: TrackUnit.h:577
TRailGraphics::sm95
Graphics::TBitmap * sm95
Definition: GraphicUnit.h:869
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:668
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:640
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4131
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:679
TAllRoutes::TLockedRouteClass::LockStartTime
TDateTime LockStartTime
the timetable time at which the route is locked, to start the 2 minute clock
Definition: TrackUnit.h:1510
TRailGraphics::DirectionNonSigRouteGraphicsPtr
Graphics::TBitmap * DirectionNonSigRouteGraphicsPtr[10]
unrestricted route marker arrows
Definition: GraphicUnit.h:1026
TRailGraphics::sm11
Graphics::TBitmap * sm11
Definition: GraphicUnit.h:764
TRailGraphics::sm125
Graphics::TBitmap * sm125
Definition: GraphicUnit.h:920
TTrack::InactiveMapCheck
bool InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:7278
TRailGraphics::gl6
Graphics::TBitmap * gl6
Definition: GraphicUnit.h:664
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1193
TRailGraphics::sm23
Graphics::TBitmap * sm23
Definition: GraphicUnit.h:794
TRailGraphics::sm55
Graphics::TBitmap * sm55
Definition: GraphicUnit.h:829
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:8637
TRailGraphics::BridgePrefDirGraphicsPtr
Graphics::TBitmap * BridgePrefDirGraphicsPtr[12]
preferred direction graphic overlay
Definition: GraphicUnit.h:1000
TRailGraphics::sm10
Graphics::TBitmap * sm10
Definition: GraphicUnit.h:753
TTrack::FindClosestLinkPosition
int FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
Return the link array position for the element at StartTVPosition that gives the closest link to the ...
Definition: TrackUnit.cpp:10030
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1484
TRailGraphics::sm41
Graphics::TBitmap * sm41
Definition: GraphicUnit.h:814
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:55
TRailGraphics::gl22
Graphics::TBitmap * gl22
Definition: GraphicUnit.h:623
TOneRoute::TRouteFlashElement::HLoc
int HLoc
Definition: TrackUnit.h:1377
TRailGraphics::bm100
Graphics::TBitmap * bm100
Definition: GraphicUnit.h:347
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:705
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:147
TRailGraphics::sm134
Graphics::TBitmap * sm134
Definition: GraphicUnit.h:779
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:141
TRailGraphics::gl71
Graphics::TBitmap * gl71
Definition: GraphicUnit.h:677
TOneRoute::TRouteFlashElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
displayed alternately during flashing
Definition: TrackUnit.h:1379
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:527
TTrack::AnyLinkedBarrierDownVectorManual
bool AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
Checks BarrierDownVector and returns true if there is one that is linked to the LC at H & V positions...
Definition: TrackUnit.cpp:5689
TRailGraphics::gl92set
Graphics::TBitmap * gl92set
Definition: GraphicUnit.h:708
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3218
TRailGraphics::sm102
Graphics::TBitmap * sm102
Definition: GraphicUnit.h:756
TRailGraphics::gl4
Graphics::TBitmap * gl4
Definition: GraphicUnit.h:642
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:98
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:111
TTrack::Tag96Array
int Tag96Array[28][3]
Definition: TrackUnit.h:498
TRailGraphics::sm15
Graphics::TBitmap * sm15
Definition: GraphicUnit.h:786
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:650
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:9962
TRailGraphics::sm13
Graphics::TBitmap * sm13
Definition: GraphicUnit.h:773
TRailGraphics::sm91
Graphics::TBitmap * sm91
Definition: GraphicUnit.h:865
TRailGraphics::sm59
Graphics::TBitmap * sm59
Definition: GraphicUnit.h:833
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:147
TTrack::TLNPendingListIterator
TLNPendingList::iterator TLNPendingListIterator
naming of linked named location elements
Definition: TrackUnit.h:591
TRailGraphics::sm114
Graphics::TBitmap * sm114
Definition: GraphicUnit.h:911
TPrefDirElement::LogPrefDir
AnsiString LogPrefDir() const
Sends a list of PrefDirElement values to Utilities->CallLog file for debugging purposes.
Definition: TrackUnit.cpp:251
TRailGraphics::gl82
Graphics::TBitmap * gl82
Definition: GraphicUnit.h:693
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:536
TRailGraphics::gl95set
Graphics::TBitmap * gl95set
Definition: GraphicUnit.h:712
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:82
TPrefDirElement::operator==
bool operator==(TPrefDirElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:850
TrainUnit.h
TRailGraphics::bm34
Graphics::TBitmap * bm34
Definition: GraphicUnit.h:412
TRailGraphics::gl104
Graphics::TBitmap * gl104
Definition: GraphicUnit.h:566
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag.=1, top=2, top rh diag....
Definition: TrackUnit.h:87
TOneRoute::SearchForNonPreferredRoute
bool SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID)
Called by GetNextNonPreferredRouteElement to carry out the search for linked track,...
Definition: TrackUnit.cpp:14914
TTrack::TLNDone2MultiMapEntry
std::pair< THVPair, int > TLNDone2MultiMapEntry
can be up to 2 entries (platforms) at a single location
Definition: TrackUnit.h:598
TTrack::TrackMap
TTrackMap TrackMap
map of track (see type for more information above)
Definition: TrackUnit.h:708
RouteCall
@ RouteCall
Definition: TrackUnit.h:1186
TRailGraphics::bm141
Graphics::TBitmap * bm141
Definition: GraphicUnit.h:387
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:10423
TRailGraphics::sm76striped
Graphics::TBitmap * sm76striped
Definition: GraphicUnit.h:845
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
look for a text item in the vicinity of HPosInput & VPosInput & if TextToErase is null then erase any...
Definition: TextUnit.cpp:250
TRailGraphics::gl127
Graphics::TBitmap * gl127
Definition: GraphicUnit.h:591
TRailGraphics::bm75yellow
Graphics::TBitmap * bm75yellow
Definition: GraphicUnit.h:501
NotSet
@ NotSet
Definition: TrackUnit.h:73
TTrack::TInactiveTrack2MultiMapIterator
TInactiveTrack2MultiMap::iterator TInactiveTrack2MultiMapIterator
iterator for TInactiveTrack2MultiMap
Definition: TrackUnit.h:581
TAllRoutes::GetAllRoutesTruncateElement
bool GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute)
Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is prese...
Definition: TrackUnit.cpp:16230
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:17237
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:88
TMapComp::operator()
bool operator()(const THVPair &lower, const THVPair &higher) const
HLoc VLoc.
Definition: TrackUnit.cpp:213
TRailGraphics::bm16
Graphics::TBitmap * bm16
Definition: GraphicUnit.h:390
TRailGraphics::gl128
Graphics::TBitmap * gl128
Definition: GraphicUnit.h:592
TRailGraphics::gl116
Graphics::TBitmap * gl116
Definition: GraphicUnit.h:579
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:9991
TTrack::TrackClear
void TrackClear(int Caller)
Empty the track and inactive track vectors, the corresponding track maps, and LocationNameMultiMap.
Definition: TrackUnit.cpp:9327
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:586
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:505
TPrefDirElement::ELink
int ELink
Definition: TrackUnit.h:213
TRailGraphics::sm130striped
Graphics::TBitmap * sm130striped
Definition: GraphicUnit.h:775
TRailGraphics::sm118
Graphics::TBitmap * sm118
Definition: GraphicUnit.h:913
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:5591
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:156
LevelCrossing
@ LevelCrossing
Definition: TrackUnit.h:64
TRailGraphics::sm126
Graphics::TBitmap * sm126
Definition: GraphicUnit.h:921
TRailGraphics::smTransparent
Graphics::TBitmap * smTransparent
Definition: GraphicUnit.h:887
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:642
TOnePrefDir::GetModifiableSearchElementAt
TPrefDirElement & GetModifiableSearchElementAt(int Caller, int At)
Return a modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:10435
TOnePrefDir::TotalSearchCount
int TotalSearchCount
counts search elements, used to abort searches (prefdirs or routes) if reaches too high a value
Definition: TrackUnit.h:1246
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:53
TRailGraphics::bm18
Graphics::TBitmap * bm18
Definition: GraphicUnit.h:391
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:141
TTrack::~TTrack
~TTrack()
Destructor.
Definition: TrackUnit.cpp:1243
TRailGraphics::sm62
Graphics::TBitmap * sm62
Definition: GraphicUnit.h:837
TRailGraphics::LCBothVer
Graphics::TBitmap * LCBothVer
Definition: GraphicUnit.h:721
TRailGraphics::sm35
Graphics::TBitmap * sm35
Definition: GraphicUnit.h:807
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TRailGraphics::gl81
Graphics::TBitmap * gl81
Definition: GraphicUnit.h:692
TTrack::HLocMax
int HLocMax
Definition: TrackUnit.h:487
TRailGraphics::gl146
Graphics::TBitmap * gl146
Definition: GraphicUnit.h:614
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:9318
Bridge
@ Bridge
Definition: TrackUnit.h:63
TRailGraphics::sm78
Graphics::TBitmap * sm78
Definition: GraphicUnit.h:848
TRailGraphics::bm43
Graphics::TBitmap * bm43
Definition: GraphicUnit.h:439
InRouteFalse
@ InRouteFalse
Definition: TrackUnit.h:1180
TRailGraphics::sm25
Graphics::TBitmap * sm25
Definition: GraphicUnit.h:796
TRailGraphics::bmName
Graphics::TBitmap * bmName
Definition: GraphicUnit.h:523
Gap
@ Gap
Definition: TrackUnit.h:73
Buffers
@ Buffers
Definition: TrackUnit.h:63
TOneRoute::SetRemainingSearchVectorValues
void SetRemainingSearchVectorValues(int Caller)
Called when setting unrestricted routes to set the route element values appropriately after a success...
Definition: TrackUnit.cpp:15220
TRailGraphics::gl79Striped
Graphics::TBitmap * gl79Striped
Definition: GraphicUnit.h:689
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:50
CrossConn
@ CrossConn
Definition: TrackUnit.h:73
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:10447
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:14558
TRailGraphics::bm71grounddblwhite
Graphics::TBitmap * bm71grounddblwhite
Definition: GraphicUnit.h:473
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4044
TOnePrefDir::LastElementNumber
int LastElementNumber(int Caller) const
Return the vector position of the last element in the vector (i.e. one less than the vector size)
Definition: TrackUnit.cpp:10370
TRailGraphics::sm58
Graphics::TBitmap * sm58
Definition: GraphicUnit.h:832